home *** CD-ROM | disk | FTP | other *** search
/ GFX Sensations 1 / Graphic Sensations - Volume 1.iso / tools / amiga / 3d_tools / t3dsrc.lha / read.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-01-21  |  76.6 KB  |  2,291 lines

  1. /* read.c - read a TTDDD file and fill the structures
  2.  *        - written by Glenn M. Lewis - 7/19/91
  3.  *        - added HINGE support: Rob Hounsell - 01/01/94
  4.  */
  5.  
  6. static char rcs_id[] = "$Id: read.c,v 1.33 1994/01/20 22:14:52 glewis Exp $";
  7.  
  8. #include <stdio.h>
  9. #include <ctype.h>
  10. #include <sys/types.h>
  11. #include "t3dlib.h"
  12. #ifdef __STDC__
  13. #include <stdlib.h>
  14. #include <strings.h>
  15. #include "read_protos.h"
  16. #endif
  17.  
  18. static void process_INFO();
  19. static void process_OBJ();
  20. static void process_ISTG();
  21. static OBJECT *process_EXTR();
  22. static void process_DESC();
  23. static OBJECT *process_MXTR();
  24. static void desc_copy();
  25. static void malloc_arrays();
  26. extern int verbose_flag;
  27. extern int already_read_header;            /* A hack to include characters */
  28. extern unsigned char header_storage[];    /* that were already read in */
  29. extern void insert_into_sorted_list();
  30.  
  31. #define MAXLINE 512
  32. #define get_UBYTE    (UBYTE)get_num
  33. #define get_UWORD    (UWORD)get_num
  34. #define get_ULONG    (ULONG)get_num
  35.  
  36. static char strin[MAXLINE+1], ps[MAXLINE+1];
  37. static UBYTE defclst[3], defrlst[3], deftlst[3], defspc1[3];
  38.  
  39. /* Here are a few necessary utilities */
  40.  
  41. static void warn(curline)
  42. int curline;
  43. {
  44.     fprintf(stderr, "WARNING: Line %d: ", curline);
  45. }
  46.  
  47. static void parse_word(name, lim, up)    /* Get next word, optionally limit # of chars */
  48. register char *name;
  49. int lim, up;
  50. {
  51.     register char *c = &strin[0];
  52.     register int i;
  53.     int quote = 0;
  54.  
  55.     while (*c==' ') c++;        /* Skip over leading spaces */
  56.     for (i=0; *c; i++,c++) {
  57.         if (lim && i>=lim) break;    /* No more characters desired */
  58.         if (*c == '\"') {            /* Chop off quotes, ignore spaces */
  59.             if (quote) break;        /* Second quote.  Stop reading string */
  60.             quote=1;
  61.             i--;                    /* Don't want i to increment */
  62.             continue;
  63.         }
  64.         if (up && !quote && islower(*c)) *name++ = toupper(*c);
  65.         else {
  66.             if (!quote && *c==' ') break;    /* End of the line */
  67.             *name++ = *c;            /* Don't modify original case */
  68.         }
  69.     }
  70.     *name = '\0';    /* Truncate the puppy */
  71.     /* Now, delete the command from 'strin' */
  72.     while (*c && *c!=' ') c++;    /* Skip the end of the command */
  73.     while (*c==' ') c++;        /* Skip mid-word spacing */
  74.     strcpy(strin, c);            /* Chop off front of line */
  75. }
  76.  
  77. static int get_line(strin, w)
  78. register char *strin;
  79. WORLD *w;
  80. {
  81.     static int comment = 0;
  82.     int quote = 0, start;
  83.     register char *c;
  84.  
  85. GET_MORE:
  86.     if (comment) start = 0; else start = -1;
  87.     if (fgets(&strin[already_read_header], MAXLINE, w->inp) == NULL) {
  88.         already_read_header = 0;
  89.         if (comment)
  90.         fprintf(stderr, "WARNING: Line %d: Unterminated comment.\n",w->cur_line);
  91.         return(0);    /* EOF */
  92.     }
  93.     already_read_header = 0;
  94.     w->cur_line++;
  95.     for (c=strin; *c; c++) {
  96.         if (*c=='/' && c[1]=='*') {            /* Begin of comment */
  97.             if (!quote) {
  98.                 if (!comment++) {            /* First comment */
  99.                     start = (int)(c-strin);
  100.                 }
  101.             }
  102.         } else
  103.         if (*c=='*' && c[1]=='/') {            /* End of comment */
  104.             if (!quote) {
  105.                 comment--;
  106.                 if (comment<0) {
  107.                     fprintf(stderr, "ERROR!  '*/' before '/*'\n*** ABORT ***\n");
  108.                     exit(20);
  109.                 }
  110.                 if (!comment) {                /* Chop off front of line */
  111.                     strcpy(strin, c+2);
  112.                     c = strin-1;            /* Pointer will increment */
  113.                 }
  114.             }
  115.         } else
  116.         if (*c=='%') {                        /* Line comment */
  117.             if (!(quote || comment)) {
  118.                 *c = '\0';                    /* Terminate line */
  119.                 break;
  120.             }
  121.         } else
  122.         if (*c =='\"') {                    /* Quote */
  123.             if (!comment) quote=1-quote;    /* Toggle flag */
  124.         } else
  125.         if (*c == '\t') *c = ' ';            /* Change tabs to spaces */
  126.         else
  127.         if (!quote && (*c=='[' || *c==']' || *c=='=')) *c = ' ';
  128.         if (*c == '\n') { *c = '\0'; break; }
  129.     }
  130.     if (comment) strin[start] = '\0';        /* Chop off comment */
  131. /* Skip leading white space to see if this line contains anything */
  132.     for (c=strin; *c==' '; c++) ;
  133.     if (!*c) goto GET_MORE;
  134.     return(1);
  135. }
  136.  
  137. static int valid_num;
  138.  
  139. static long get_num()
  140. {
  141.     long val = 0;
  142.     char neg = ' ';
  143.     register char *c = &strin[0];
  144.  
  145.     valid_num = 0;
  146.     while (*c == ' ') c++;        /* Skip leading space */
  147.     if (*c == '-') neg = *c++;    /* Save the negation  */
  148.     if (!isdigit(*c)) return(0L);
  149.     while (*c && isdigit(*c))
  150.         val = (val*10) + (*c++ - '0');
  151.     while (*c == ' ') c++;        /* Skip trailing space */
  152.     strcpy(strin, c);            /* Chop off number */
  153.     valid_num = 1;
  154.     return((neg=='-' ? -val : val));
  155. }
  156.  
  157. static int valid_FRACT;
  158.  
  159. static double get_FRACT()
  160. {
  161.     register long whole, expo;
  162.     register char *s = &strin[0];
  163.     char neg=' ', negexp=' ';
  164.     double f, frac, place;
  165.  
  166.     valid_FRACT = 0;
  167.     whole = expo = 0;
  168.     while (*s == ' ') s++;
  169.     if (*s == '-') neg = *s++;
  170.     if (!isdigit(*s) && *s!='.') return(0L);    /* Invalid FRACT */
  171.     while (*s && isdigit(*s))        /* Handle float before decimal point */
  172.         whole = (whole * 10) + (*s++ - '0');
  173.     if (*s == '.') {        /* Handle float after decimal point */
  174.         s++;
  175.         frac = 0.0;
  176.         for (place=10.0; *s && isdigit(*s); place*=10.0)
  177.             frac +=  (*s++ - '0')/place;
  178.         f = (double)whole + frac;
  179.     } else f = (double)whole;
  180.     if (*s == 'e' || *s == 'E') {    /* Support exponential notation */
  181.         s++;
  182.         if (*s=='-' || *s=='+') negexp = *s++;
  183.         while (*s && isdigit(*s)) expo = (expo*10) + (*s++ - '0');
  184.         if (negexp=='-')    while (expo--) f/=10.0;
  185.         else                while (expo--) f*=10.0;
  186.     }
  187.     while (*s == ' ') s++;
  188.     strcpy(strin, s);
  189.     valid_FRACT = 1;
  190.     return((neg=='-' ? -f : f));
  191. }
  192.  
  193. static void stage_RGB(st)
  194. XYZ_st *st;
  195. {
  196.     register char *c = &strin[0];
  197.     register int i, flag, cnt;
  198.  
  199.     flag = 0;    /* If they use 'R','G', or 'B', they must continue to use it */
  200.     /* On the other hand, if they give only a single parameter, then it applies to all */
  201.     cnt = 0;
  202.     for (i=0; i<3; i++) {
  203.         if (*c=='r' || *c=='R')        /* If !valid, it's an ERROR! */
  204.         { *c=' '; st->x = get_FRACT(); if (valid_FRACT) flag=1; }
  205.         else
  206.         if (*c=='g' || *c=='G')
  207.         { *c=' '; st->y = get_FRACT(); if (valid_FRACT) flag=1; }
  208.         else
  209.         if (*c=='b' || *c=='B')
  210.         { *c=' '; st->z = get_FRACT(); if (valid_FRACT) flag=1; }
  211.         else if (!flag) {
  212.             if (i==0)        st->x = get_FRACT();
  213.             else if (i==1)    st->y = get_FRACT();
  214.             else            st->z = get_FRACT();
  215.             if (valid_FRACT) cnt++;
  216.         }
  217.     }
  218.     if (!flag && cnt==1) {     /* Copy value into other two elements */
  219.         st->y = st->z = st->x;
  220.     }
  221. }
  222.  
  223. static void stuff_XYZ(st)
  224. XYZ_st *st;
  225. {
  226.     register char *c = &strin[0];
  227.     register int i, flag, cnt;
  228.  
  229.     flag = 0;    /* If they use 'X','Y', or 'Z', they must continue to use it */
  230.     /* On the other hand, if they give only a single parameter, then it applies to all */
  231.     cnt = 0;
  232.     for (i=0; i<3; i++) {
  233.         if (*c=='x' || *c=='X')        /* If !valid, it's an ERROR! */
  234.         { *c=' '; st->x = get_FRACT(); if (valid_FRACT) flag=1; }
  235.         else
  236.         if (*c=='y' || *c=='Y')
  237.         { *c=' '; st->y = get_FRACT(); if (valid_FRACT) flag=1; }
  238.         else
  239.         if (*c=='z' || *c=='Z')
  240.         { *c=' '; st->z = get_FRACT(); if (valid_FRACT) flag=1; }
  241.         else if (!flag) {
  242.             if (i==0)        st->x = get_FRACT();
  243.             else if (i==1)    st->y = get_FRACT();
  244.             else            st->z = get_FRACT();
  245.             if (valid_FRACT) cnt++;
  246.         }
  247.     }
  248.     if (!flag && cnt==1) {     /* Copy value into other two elements */
  249.         st->y = st->z = st->x;
  250.     }
  251. }
  252.  
  253. static void stuff_RGB(st)
  254. RGB_st *st;
  255. {
  256.     register char *c = &strin[0];
  257.     register int i, flag, cnt;
  258.  
  259.     flag = 0;    /* If they use 'R','G', or 'B', they must continue to use it */
  260.     /* On the other hand, if they give only a single parameter, then it applies to all */
  261.     cnt = 0;
  262.     for (i=0; i<3; i++) {
  263.         if (*c=='r' || *c=='R')        /* If !valid, it's an ERROR! */
  264.         { *c=' '; st->r = get_UBYTE(); if (valid_num) flag=1; }
  265.         else
  266.         if (*c=='g' || *c=='G')
  267.         { *c=' '; st->g = get_UBYTE(); if (valid_num) flag=1; }
  268.         else
  269.         if (*c=='b' || *c=='B')
  270.         { *c=' '; st->b = get_UBYTE(); if (valid_num) flag=1; }
  271.         else if (!flag) {
  272.             if (i==0)        st->r = get_UBYTE();
  273.             else if (i==1)    st->g = get_UBYTE();
  274.             else            st->b = get_UBYTE();
  275.             if (valid_num) cnt++;
  276.         }
  277.     }
  278.     if (!flag && cnt==1) {     /* Copy value into other two elements */
  279.         st->g = st->b = st->r;
  280.     }
  281. }
  282.  
  283. /********************/
  284. /* The MAIN section */
  285. /********************/
  286.  
  287. WORLD *read_TTDDD(file)
  288. FILE *file;
  289. {
  290.     char name[5];
  291.     WORLD *world;
  292.  
  293.     if (!file) return(0L); /* File not open */
  294.  
  295.     if (!(world = (WORLD*)malloc(sizeof(WORLD)))) { OUT_MEM("WORLD"); }
  296.     bzero((char*)world, sizeof(WORLD));
  297.     world->inp = file;
  298.  
  299.     if (already_read_header)    /* Copy the data into the "strin" */
  300.         strncpy(strin, header_storage, already_read_header);
  301.  
  302. /* Here is the main loop: */
  303.     while (get_line(strin, world)) {
  304.         parse_word(name, 4, 1);        /* And chop it out of the string */
  305.  
  306.         if        (strcmp(name, "INFO")==0) process_INFO(world);
  307.         else if (strcmp(name, "OBJ") ==0) process_OBJ(world);
  308.         else if (strcmp(name, "ISTG")==0) process_ISTG(world);
  309.         else {
  310.             fprintf(stderr, "Invalid chunk on line %d: '%s' (skipped)\n",
  311.                 world->cur_line, name);
  312.             continue;
  313.         }
  314.     }
  315.  
  316. /* All done.  Close up shop. */
  317.     return(world);
  318. }
  319.  
  320. static void process_INFO(world)
  321. WORLD *world;
  322. {
  323.     register INFO *info;
  324.     register ULONG i;
  325.     char this_level[MAXLINE], name[5];
  326.  
  327.     if (world->info) {
  328.         fprintf(stderr, "Parse error: More than one INFO chunk!\n"); exit(-1); }
  329.     if (!(info = world->info = (INFO*)malloc(sizeof(INFO)))) { OUT_MEM("INFO"); }
  330.     bzero((char *)world->info, sizeof(INFO));
  331.  
  332.     parse_word(this_level, 0, 1);    /* No limit, uppercase. */
  333.     if (strcmp(this_level, "BEGIN") != 0) {
  334.         fprintf(stderr, "WARNING: Line %d: Bad syntax.  Missing 'Begin' after 'INFO'\n",
  335.             world->cur_line);
  336.     }
  337.     parse_word(this_level, 0, 0);    /* No limit, original case */
  338.  
  339.     while (get_line(strin, world)) {
  340.         parse_word(name, 4, 1);        /* Get command */
  341.         if (strcmp(name, "BRSH")==0) {
  342.             i = get_UWORD();
  343.             if (i<0 || i>7) fputs("BRSH error.\n", stderr);
  344.             parse_word(ps, 0, 0);
  345.             strncpy(info->brsh[i], ps, 80);
  346.             info->brsh[i][80]='\0';
  347.         } else
  348.         if (strcmp(name, "STNC")==0) {
  349.             i = get_UWORD();
  350.             if (i<0 || i>7) fputs("STNC error.\n", stderr);
  351.             parse_word(ps, 0, 0);
  352.             strncpy(info->stnc[i], ps, 80);
  353.             info->stnc[i][80]='\0';
  354.         } else
  355.         if (strcmp(name, "TXTR")==0) {
  356.             i = get_UWORD();
  357.             if (i<0 || i>7) fputs("TXTR error.\n", stderr);
  358.             parse_word(ps, 0, 0);
  359.             strncpy(info->txtr[i], ps, 80);
  360.             info->txtr[i][80]='\0';
  361.         } else
  362.         if (strcmp(name, "OBSV")==0) {
  363.             if (!info->obsv) info->obsv=(OBSV*)malloc(sizeof(OBSV));
  364.             if (!info->obsv) { OUT_MEM("OBSV"); }
  365.             parse_word(name, 4, 1);        /* Get field */
  366.             if        (strcmp(name, "CAME")==0) stuff_XYZ(&info->obsv->came);
  367.             else if (strcmp(name, "ROTA")==0) stuff_XYZ(&info->obsv->rota);
  368.             else if (strcmp(name, "FOCA")==0) info->obsv->foca = get_FRACT();
  369.             else {
  370.                 if (verbose_flag)
  371.                     fprintf(stderr, "WARNING: Line %d: Unknown OBSV field: '%s'\n",
  372.                         world->cur_line, name);
  373.                 continue;
  374.             }
  375.         } else
  376.         if (strcmp(name, "OTRK")==0) {
  377.             parse_word(ps, 0, 0);
  378.             strncpy(info->otrk, ps, 18);
  379.             info->otrk[18]='\0';
  380.         } else
  381.         if (strcmp(name, "OSTR")==0) {
  382.             if (!info->ostr) info->ostr=(STRY*)malloc(sizeof(STRY));
  383.             if (!info->ostr) { OUT_MEM("OSTR"); }
  384.             parse_word(name, 4, 1);        /* Get field */
  385.             if (strcmp(name, "PATH")==0) parse_word(info->ostr->path, 18, 0);
  386.             else if (strcmp(name, "TRAN")==0) stuff_XYZ(&info->ostr->tran);
  387.             else if (strcmp(name, "ROTA")==0) stuff_XYZ(&info->ostr->rota);
  388.             else if (strcmp(name, "SCAL")==0) stuff_XYZ(&info->ostr->scal);
  389.             else
  390.             if (strcmp(name, "INFO")==0) {
  391.                 info->ostr->info = 0;
  392.                 while (strin[0]) {
  393.                     parse_word(ps, 7, 1);
  394.                     if        (strcmp(ps, "ABS_TRA")==0) info->ostr->info|=(1<<0);
  395.                     else if (strcmp(ps, "ABS_ROT")==0) info->ostr->info|=(1<<1);
  396.                     else if (strcmp(ps, "ABS_SCL")==0) info->ostr->info|=(1<<2);
  397.                     else if (strcmp(ps, "LOC_TRA")==0) info->ostr->info|=(1<<4);
  398.                     else if (strcmp(ps, "LOC_ROT")==0) info->ostr->info|=(1<<5);
  399.                     else if (strcmp(ps, "LOC_SCL")==0) info->ostr->info|=(1<<6);
  400.                     else if (strcmp(ps, "X_ALIGN")==0) info->ostr->info|=(1<<8);
  401.                     else if (strcmp(ps, "Y_ALIGN")==0) info->ostr->info|=(1<<9);
  402.                     else if (strcmp(ps, "Z_ALIGN")==0) info->ostr->info|=(1<<10);
  403.                     else if (strcmp(ps, "FOLLOW_")==0) info->ostr->info|=(1<<12);
  404.                     else {
  405.                         if (verbose_flag)
  406.                             fprintf(stderr, "WARNING: Line %d: Unknown OSTR INFO flag: '%s'\n",
  407.                                 world->cur_line, ps);
  408.                         continue;
  409.                     }
  410.                 }
  411.             } else {
  412.                 if (verbose_flag)
  413.                     fprintf(stderr, "WARNING: Line %d: Unknown OSTR field: '%s'\n",
  414.                         world->cur_line, name);
  415.                 continue;
  416.             }
  417.         } else
  418.         if (strcmp(name, "FADE")==0) {
  419.             if (!info->fade) info->fade=(FADE*)malloc(sizeof(FADE));
  420.             if (!info->fade) { OUT_MEM("FADE"); }
  421.             parse_word(ps, 6, 1);        /* Get field */
  422.             if        (strcmp(ps, "FADEAT")==0) info->fade->at = get_FRACT();
  423.             else if (strcmp(ps, "FADEBY")==0) info->fade->by = get_FRACT();
  424.             else if (strcmp(ps, "FADETO")==0) stuff_RGB(&info->fade->to);
  425.             else {
  426.                 if (verbose_flag)
  427.                     fprintf(stderr, "WARNING: Line %d: Unknown FADE field: '%s'\n",
  428.                         world->cur_line, ps);
  429.                 continue;
  430.             }
  431.         } else
  432.         if (strcmp(name, "SKYC")==0) {
  433.             if (!info->skyc) info->skyc=(SKYC*)malloc(sizeof(SKYC));
  434.             if (!info->skyc) { OUT_MEM("SKYC"); }
  435.             parse_word(name, 4, 1);        /* Get field */
  436.             if        (strcmp(name, "HORI")==0) stuff_RGB(&info->skyc->hori);
  437.             else if (strcmp(name, "ZENI")==0) stuff_RGB(&info->skyc->zeni);
  438.             else {
  439.                 if (verbose_flag)
  440.                     fprintf(stderr, "WARNING: Line %d: Unknown SKYC field: '%s'\n",
  441.                         world->cur_line, name);
  442.                 continue;
  443.             }
  444.         } else
  445.         if (strcmp(name, "AMBI")==0) {
  446.             if (!info->ambi) info->ambi=(RGB_st*)malloc(sizeof(RGB_st));
  447.             if (!info->ambi) { OUT_MEM("AMBI"); }
  448.             stuff_RGB(info->ambi);
  449.         } else
  450.         if (strcmp(name, "GLB0")==0) {
  451.             if (!info->glb0) info->glb0=(BYTE*)malloc(8*sizeof(BYTE));
  452.             if (!info->glb0) { OUT_MEM("GLB0"); }
  453.             i = get_ULONG();    /* Index into array */
  454.             if (i>=0 && i<8) {
  455.                 info->glb0[i] = (BYTE) get_ULONG();
  456.             } else
  457.                 fprintf(stderr, "WARNING: Line %d: Bad index: GLB0[%d] should be [0..7]\n", world->cur_line, i);
  458.         } else if (strcmp(name, "END")==0) {
  459.             parse_word(name, 4, 1);
  460.             if (strcmp(name, "INFO")!=0)
  461.                 fprintf(stderr, "WARNING: Line %d: Expected 'END INFO' but got: 'END %s'\n", world->cur_line, name);
  462.             parse_word(ps, 0, 0);    /* Get the quote, if any */
  463.             if (strcmp(this_level, ps)!=0)
  464.                 fprintf(stderr, "WARNING: Line %d: 'INFO Begin' and 'End INFO' quoted comments do not match\n", world->cur_line);
  465.             break;
  466.         } else if (verbose_flag)
  467.             fprintf(stderr, "WARNING: Line %d: Unknown INFO sub-sub-chunk: '%s'\n",
  468.                 world->cur_line, name);
  469.     }
  470. }
  471.  
  472. OBJECT *create_object()
  473. {
  474.     OBJECT *p;
  475.     p = (OBJECT*)malloc(sizeof(OBJECT));
  476.     if (!p) { OUT_MEM("Create"); }
  477.     bzero((char*)p,sizeof(OBJECT));
  478.     return(p);
  479. }
  480.  
  481. static void process_OBJ(world)
  482. WORLD *world;
  483. {
  484.     char this_level[MAXLINE], name[5];
  485.     register OBJECT *p;
  486.     int depth;
  487.  
  488.     parse_word(this_level, 0, 1);    /* No limit, uppercase. */
  489.     if (strcmp(this_level, "BEGIN") != 0) {
  490.         fprintf(stderr, "WARNING: Line %d: Bad syntax.  Missing 'Begin' after 'OBJ'\n",
  491.             world->cur_line);
  492.     }
  493.     parse_word(this_level, 0, 0);    /* No limit, original case */
  494.  
  495.     depth=0;
  496.     while (get_line(strin, world)) {
  497.         parse_word(name, 4, 1);        /* Get command */
  498.         if        (strcmp(name, "EXTR")==0) {
  499.             p = process_EXTR(create_object(), world);
  500.             if (world->curobj) {
  501.                 world->curobj->next = p;
  502.                 p->parent = world->curobj->parent;
  503.             } else {
  504.                 world->object = p;
  505.                 p->parent = 0;
  506.             }
  507.             world->curobj = p;
  508.         
  509. /*
  510.  
  511. Glenn:
  512.     Here is the merging code.  I also tried loading grouped objects into
  513. the detail editor, with similar results to what I was seeing when I was loading
  514. massive numbers of separate objects.  Results are below, but I think this will
  515. complicate our lives considerably.
  516.     Cheers,
  517.     Charles
  518.  
  519. ------------------------------------------------------------------------------
  520. Charles Congdon                                      Oracle Corporation
  521. Special Projects                                     2580 SW 192nd Ave.
  522. Midrange Systems Group, DEC Products Division        Aloha, OR   97006
  523. Office:  (415) 506-6341                              FAX:  (415) 506-6341
  524. Internet:  ccongdon@us.oracle.com               Usenet:  uunet!oracle!ccongdon
  525. ------------------------------------------------------------------------------
  526.  
  527.              MODIFICATIONS TO READ.C TO SUPPORT MXTR CHUNKS
  528.          ==============================================
  529.  
  530. Purpose:
  531.  
  532.     These routines allow the following construct:
  533.     
  534.     MXTR Begin
  535.     
  536.     EXTR Begin
  537.     <etc>
  538.     End EXTR
  539.     
  540.     EXTR Begin
  541.     <etc>
  542.     End EXTR
  543.     
  544.     EXTR Begin
  545.     <etc>
  546.     End EXTR
  547.     :
  548.     :
  549.     :
  550.     
  551.     End MXTR
  552.  
  553. Everything within the MXTR chunk is merged into one huge object.  Over
  554. 750 objects have been merged with this code, resulting in objects with
  555. point, face, and edge counts in the mid-thousands (oh yes, and over
  556. 1400 subgroups!).  I really mean "merge" here, not group. 
  557.  
  558. The last EXTR object in the list defines the face-insensitive
  559. attributes like hardness, specular, etc. for the entire mega object.
  560. NOTE:  this implies that if you are merging two EXTR objects, one with
  561. a zero hardness, and one with a hardness of 255, then which ever is
  562. the last in the list before End MXTR defines the hardness for all.  In
  563. short, don't merge objects with vastly differing face-insensitive
  564. attributes (for example, chrome and rubber).
  565.  
  566. All component EXTR objects contribute to fill in the face-sensitive
  567. attributes (point, edge, face, color, reflect, and filter information)
  568. for the object (i.e. - all face-specific attributes are preserved for
  569. all faces of all component EXTR objects).  Yes, that includes all
  570. subgroups defined for all component EXTR objects.  Names of subgroups
  571. will be "mangled" with a counter to better let you identify who to
  572. change.  I considered merging subgroups (since they can build up
  573. fast), but figured that is best for a future enhancement. 
  574.  
  575. Face-sensitive "attributes" that were thrown out entirely are textures
  576. and brushmaps.  The reason is that these are limited to 4 per object.
  577. What do you do when you merge 1000 objects, each with three textures
  578. defined?  Which 4 textures do you use?  What should the texture axis
  579. positions be?  How about the texture scale factors?  In short, apply
  580. your textures to your merged object (using subgroups if you wish to
  581. restrict the scope) once you have loaded it into Imagine. 
  582.  
  583. Another limitation is that at present I do not support heirachical
  584. EXTR objects.  If you look at the length of the code below, I think
  585. you will understand why.  To do so, simply unroll the heirarchy into
  586. the master object.  This will require an additional preprocessing step
  587. to properly calculate point, edge, and face counts, and some recursion
  588. in the main copying loop.  NOTE:  By not preserve I mean two things:
  589. 1) at present I only copy the parent of an EXTR object that is
  590. actually a group.  2) I don't try to build heirarchy into the merged
  591. object either. 
  592.  
  593. Why not *preserve* heirachies, you ask?  Because Imagine reacts poorly
  594. to the creation of massive numbers of objects at a time.  Loading any
  595. more than 100-300 objects at a time into the detail results in a wait
  596. that can stretch on for hours as Imagine sets up for fast access to
  597. these objects.  The objects all happily draw in the tri-view window
  598. almost instantly, but the pointer remains BUSY for a *long* time.
  599. Once the BUSY pointer vanishes, Imagine draws the wireframe appears in
  600. the perspective window.   From that point on, access to all objects in
  601. the detail editor acts normally.
  602.  
  603. For example, adding 128 grouped objects in the detail editor (by a
  604. simple paste operation from a copy of an existing set of 128 grouped
  605. objects) resulted in a wait of over 5 minutes on a vanilla A3000 with
  606. 14M.  Over 11M remained free.  Loading 256 objects resulted in a wait
  607. of 15 minutes (over 9 M remained free).  These were 4 point, 6 edge, 2
  608. face objects.  The wait seems to go up as a high power of object
  609. complexity.  Loading 243 objects only twice as complex took longer
  610. than 1/2 - 3/4 hours, at which time I gave up and rebooted.   Nothing
  611. else was happening on the machine at the time.
  612.  
  613. Also, I wrote this code to allow the merging of massive numbers of
  614. *simple*, nearly identical objects.  You know, so I can merge blades
  615. of grass to make a lawn.  Or many individual leaves to make a leafy
  616. tree.  In this case, the above limitation clamps down on one fast.  If
  617. you want to merge only 40 EXTR objects, with a group of a parent and
  618. two children objects each - fine, write a GXTR chunk to handle this -
  619. 120 objects is managable, barely.  But any more than this and you
  620. should reconsider what you are trying to do. 
  621.  
  622. Hence, no groups of objects when merging (although you are free to
  623. change this - just don't break the existing functionality of MXTR)
  624.  
  625. 2)  An addition to process_OBJ(world):
  626.  
  627. */
  628.  
  629.                 /*--------------------------------------------\        
  630.                 |  Charles' magical EXTR object merge hack.   |
  631.                 \--------------------------------------------*/
  632.         } else if (strcmp(name, "MXTR")==0) {
  633.             p = process_MXTR(create_object(), world);
  634.             if (world->curobj) {
  635.                 world->curobj->next = p;
  636.                 p->parent = world->curobj->parent;
  637.             } else {
  638.                 world->object = p;
  639.                 p->parent = 0;
  640.             }
  641.             world->curobj = p;
  642.  
  643.                 /*---------------------------------------------------\        
  644.                 |  End of Charles' magical EXTR object merge hack.   |
  645.                 \---------------------------------------------------*/
  646.  
  647.         } else if (strcmp(name, "DESC")==0) {
  648.             p = create_object();
  649.             if (world->num_DESC > world->num_TOBJ+depth) {    /* This is a child */
  650.                 depth++;    /* Down one in the hierarchy */
  651.                 world->curobj->child = p;
  652.                 p->parent = world->curobj;
  653.             } else {
  654.                 if (world->curobj) {
  655.                     world->curobj->next = p;
  656.                     p->parent = world->curobj->parent;
  657.                 } else {
  658.                     world->object = p;
  659.                     p->parent = 0;
  660.                 }
  661.             }
  662.             world->curobj = p;
  663.             process_DESC(&p->desc, world);
  664.         } else if (strcmp(name, "TOBJ")==0) {
  665.             world->num_TOBJ++;
  666.             if (world->num_TOBJ > world->num_DESC) {
  667.                 warn(world->cur_line);
  668.                 fprintf(stderr, "TOBJ without DESC.  Ignored.\n");
  669.             }
  670.             if (world->num_TOBJ+depth > world->num_DESC) {    /* Go back up a level */
  671.                 depth--;
  672.                 world->curobj=world->curobj->parent;
  673.             }
  674.         } else if (strcmp(name, "END" )==0) {
  675.             if (world->num_DESC > world->num_TOBJ) {
  676.                 int i;
  677.                 warn(world->cur_line);
  678.                 i = world->num_DESC - world->num_TOBJ;
  679.                 fprintf(stderr, "Missing %d 'TOBJ'.  Inserted.\n", i);
  680.             }
  681.             parse_word(name, 4, 1);
  682.             if (strcmp(name, "OBJ")!=0)
  683.                 fprintf(stderr, "WARNING: Line %d: Expected 'END OBJ' but got: 'END %s'\n", world->cur_line, name);
  684.             parse_word(ps, 0, 0);    /* Get the quote, if any */
  685.             if (strcmp(this_level, ps)!=0)
  686.                 fprintf(stderr, "WARNING: Line %d: 'OBJ Begin' and 'End OBJ' quoted comments do not match\n", world->cur_line);
  687.             break;
  688.         } else if (verbose_flag)
  689.             fprintf(stderr, "WARNING: Line %d: Unknown OBJ sub-sub-chunk: '%s'\n",
  690.                 world->cur_line, name);
  691.     }
  692. }
  693.  
  694. /*---------------------------------------------------------\
  695. |  How to merge EXTR objects into a single mega object.    |
  696. \---------------------------------------------------------*/
  697. static OBJECT *process_MXTR(obj, world)
  698. OBJECT *obj;
  699. WORLD  *world;
  700. {    /* process_MXTR */
  701.         register OBJECT   *p, *base, *end;
  702.         register DESC     *desc, *edesc;
  703.         char              this_level[MAXLINE], name[5], nummy[8];
  704.         ULONG             pcount, ecount, fcount;
  705.         ULONG             pstart, estart, fstart;
  706.         ULONG             i;
  707.         XYZ_st            *crd, *ocrd;
  708.         ULONG             fcnt, ecnt, extrcount;
  709.         FGRP              *fgrp, *ofgrp;
  710.  
  711.         pcount = ecount = fcount = 0;
  712.         
  713.         /*---------------------------------------------------------------------\
  714.         |  Set up place-holder object - we store all EXTR objects in a linked  |
  715.         |  list, then merge into obj once we hit END MXTR.                     |
  716.         \---------------------------------------------------------------------*/
  717.         base = create_object();
  718.  
  719.         base->parent = (struct OBJECT *)0;
  720.         end = base;
  721.  
  722.         parse_word(this_level, 0, 1);   /* No limit, uppercase. */
  723.         if (strcmp(this_level, "BEGIN") != 0) {
  724.                 fprintf(stderr, "WARNING: Line %d: Bad syntax.  Missing 'Begin' after 'MXTR'\n",
  725.                         world->cur_line);
  726.         }
  727.         parse_word(this_level, 0, 0);   /* No limit, original case */
  728.         
  729.         /*---------------------------------------------------------------\      
  730.         |  Get EXTR objects to merge until END MXTR.  Any other chuck    |
  731.         |  ignored.                                                      |
  732.         \---------------------------------------------------------------*/
  733.  
  734.         while (get_line(strin, world)) {
  735.                 parse_word(name, 4, 1);         /* Get command */
  736.                 if   (strcmp(name, "EXTR")==0) {
  737.                    /*-----------------------------------------------------\             
  738.                    |  Read all EXTR objects that make up this "group".    |
  739.                    \-----------------------------------------------------*/
  740.                    p = process_EXTR(create_object(), world);
  741.                    pcount = pcount + p->desc->pcount;
  742.                    ecount = ecount + p->desc->ecount;
  743.                    fcount = fcount + p->desc->fcount;
  744.                    end->next = p;
  745.                    p->parent = end;
  746.                    end = p;
  747.                 } else if (strcmp(name, "END" )==0) {
  748.                   /*-------------------------------------\              
  749.                   |  End off this EXTR object series.    |
  750.                   \-------------------------------------*/
  751.                   parse_word(name, 4, 1);  
  752.                   if (strcmp(name, "MXTR")!=0)
  753.                      fprintf(stderr, "WARNING: Line %d: Expected 'END MXTR' but got: 'END %s'\n", world->cur_line, name);
  754.                   parse_word(ps, 0, 0); /* Get the quote, if any */
  755.                   if (strcmp(this_level, ps)!=0)
  756.                         fprintf(stderr, "WARNING: Line %d: 'MXTR Begin' and 'End MXTR' quoted comments do not match\n", world->cur_line);
  757.                   break;
  758.                 }
  759.         }   /* while MXTR */
  760.  
  761.  
  762.          /*-------------------------------------------------\   
  763.          |  OK, cap base object for our collection scan.    |
  764.          \-------------------------------------------------*/
  765.          end->next = (struct OBJECT *)0;
  766.  
  767.          end = base->next;   /* Return to first object */
  768.          base->next = (struct OBJECT *)0;  /* Since when it comes time to
  769.                                        free, this is all that will be left */
  770.          edesc = end->desc;
  771.          
  772.          /*----------------------------\
  773.          |  Set up our mega object.    |
  774.          \----------------------------*/
  775.          if (!(desc = (DESC*)malloc(sizeof(DESC)))) { OUT_MEM("DESC"); }
  776.          bzero((char*)desc, sizeof(DESC));
  777.          obj->desc = desc;
  778.  
  779.          /*-------------------------------------------------------\
  780.          |  Copy all attributes from 1st object in EXTR chain.    |
  781.          \-------------------------------------------------------*/
  782.          desc_copy(edesc, desc);        
  783.  
  784.          
  785.          /*------------------------\     
  786.          |  Set a few defaults.    |
  787.          \------------------------*/
  788.  
  789.          /* Set up defaults: */
  790.          defclst[0] = defclst[1] = defclst[2] = 240;    /* TS default */
  791.          defrlst[0] = defrlst[1] = defrlst[2] = 0;
  792.          deftlst[0] = deftlst[1] = deftlst[2] = 0;
  793.          defspc1[0] = defspc1[1] = defspc1[2] = 0;
  794.  
  795.          desc->pcount = pcount;
  796.          desc->ecount = ecount;
  797.  
  798.          /*----------------------------------------------------\
  799.          |  Allocate space for point, face, and edge arrays.   |
  800.          \----------------------------------------------------*/
  801.          if (!(desc->pnts = (XYZ_st*)malloc(desc->pcount*sizeof(XYZ_st))))
  802.                                 OUT_MEM("PNTS");
  803.          /* Initialize array */
  804.          for (i=0; i<desc->pcount; i++) {
  805.              desc->pnts[i].x = 0;
  806.              desc->pnts[i].y = 0;
  807.              desc->pnts[i].z = 0;
  808.          }
  809.  
  810.          if (!(desc->edge = (UWORD*)malloc(2*desc->ecount*sizeof(UWORD))))
  811.                                 OUT_MEM("EDGE");
  812.          /* Initialize array */
  813.          for (i=0; i<2*desc->ecount; i++)
  814.              desc->edge[i] = 0;
  815.  
  816.          malloc_arrays(fcount, desc);
  817.  
  818.          /*---------------------------------------------------------\
  819.          |  Now walk down objects, copying point, face, edge,       |
  820.          |  color, transparancy, and reflectivity information.      |
  821.          |  All other attributes have been stolen from the first    |
  822.          |  object.  Subobjects are copied                          |
  823.          |  POTENTIAL BUG:  I AM ASSUMING THE EXTR OBJECTS WE READ  |
  824.          |  HERE ARE NOT THEMSELVES HIERACHIES.   MIGHT NEED SOME   |
  825.          |  RECURSION, OR SOMETHING SIMILAR, IF THIS IS THE CASE.   |
  826.          \---------------------------------------------------------*/
  827.          ocrd = desc->pnts;
  828.          
  829.          pstart = estart = fstart = 0;
  830.          fcnt = ecnt = extrcount = 0;
  831.  
  832.          while (end != (struct OBJECT *)0)
  833.          {     /* For all objects to merge */
  834.             edesc = end->desc;
  835.             /*---------------------------------------------------------------\    
  836.             |  Copy points over - OK, I could use BCOPY, but I want control. |
  837.             \---------------------------------------------------------------*/
  838.             crd = edesc->pnts;
  839.             for (i = 0; i < edesc->pcount; i++)
  840.             {
  841.                ocrd->x = crd->x;
  842.                ocrd->y = crd->y;
  843.                ocrd->z = crd->z;
  844.                ocrd++;
  845.                crd++;
  846.             }
  847.             
  848.             /*---------------\      
  849.             |  Now edges.    |
  850.             \---------------*/
  851.             
  852.             for (i=0; i<2*edesc->ecount; i++)
  853.             {
  854.                desc->edge[ecnt] = edesc->edge[i] + pstart;
  855.                ecnt++;
  856.             }
  857.                
  858.             /*----------------------------------------------\       
  859.             |  And the faces and their basic attributes.    |
  860.             \----------------------------------------------*/
  861.             for (i = 0; i<3*edesc->fcount; i+=3)
  862.             {
  863.                desc->face[fcnt]   = edesc->face[i] + estart;
  864.                desc->face[fcnt+1] = edesc->face[i+1] + estart;
  865.                desc->face[fcnt+2] = edesc->face[i+2] + estart;
  866.                desc->clst[fcnt]   = edesc->clst[i];
  867.                desc->clst[fcnt+1] = edesc->clst[i+1];
  868.                desc->clst[fcnt+2] = edesc->clst[i+2];
  869.                desc->rlst[fcnt]   = edesc->rlst[i];
  870.                desc->rlst[fcnt+1] = edesc->rlst[i+1];
  871.                desc->rlst[fcnt+2] = edesc->rlst[i+2];
  872.                desc->tlst[fcnt]   = edesc->tlst[i];
  873.                desc->tlst[fcnt+1] = edesc->tlst[i+1];
  874.                desc->tlst[fcnt+2] = edesc->tlst[i+2];
  875.                fcnt+=3;
  876.             }
  877.             
  878.             /*----------------------------------\           
  879.             |  And the subgroup definitions.    |
  880.             \----------------------------------*/
  881.             if (edesc->fgrp)
  882.             {       /* Do subgroups */
  883.                fgrp = edesc->fgrp;
  884.                while (fgrp != (FGRP *) 0)
  885.                {    /* While subgroups to copy */
  886.                   /*------------------------\       
  887.                   |  Get FGRP structure.    |
  888.                   \------------------------*/
  889.                   if (!(ofgrp = (FGRP*)malloc(sizeof(FGRP))))
  890.                                OUT_MEM("FGRP");
  891.                   /*------------------------------\
  892.                   |  Fill out name and number.    |
  893.                   \------------------------------*/
  894.                   bzero((char *)ofgrp, sizeof(FGRP));
  895.                   
  896.                   ofgrp->num = fgrp->num;
  897.                   
  898.                   /*-----------------------------------------------\              
  899.                   |  Mangle name so unique for each subobject of   |
  900.                   |  each component EXTR object.                   |
  901.                   \-----------------------------------------------*/
  902.                   i = strlen(fgrp->name);
  903.                   if (i > 13)   /* The name field is 18 characters  */
  904.                      i = 13;    /* tops, and we remove 5 characters for
  905.                                        the ASCII representations of 0-65535 */
  906.                   strncpy(ofgrp->name, fgrp->name, i);
  907.                   ofgrp->name[i] = '\0';   /* Arrays start at 0 */
  908.                   sprintf(nummy, "%d", extrcount);
  909.                   strcat(ofgrp->name, nummy);   /* uniquely tag subgroup
  910.                                                    name by number of parent
  911.                                                    EXTR object */
  912.                   
  913.                   /*-----------------------------\                
  914.                   |  Insert into linked list.    |
  915.                   \-----------------------------*/
  916.                   ofgrp->next = desc->fgrp;
  917.                   desc->fgrp = ofgrp;
  918.                      
  919.                   /*-----------------------------------\                  
  920.                   |  And copy in the face indicies.    |
  921.                   \-----------------------------------*/
  922.                   if (!(ofgrp->face = 
  923.                            (UWORD *)malloc((fgrp->num)*sizeof(UWORD))))
  924.                                         OUT_MEM("FGRP");
  925.                   for (i = 0; i < fgrp->num; i++)
  926.                   {
  927.                      ofgrp->face[i] = (UWORD) (fgrp->face[i] + fstart);
  928.                   }
  929.                   
  930.                   fgrp = fgrp->next;
  931.                }    /* While subgroups to copy */
  932.             }       /* Do subgroups */
  933.  
  934.             /*-------------------------------------------------------\      
  935.             |  Copying textures in a similar manner would be         |
  936.             |  rather difficult, since we can only have 4 textures   |
  937.             |  per object.  I suggest having the user make their     |
  938.             |  own subgroups and apply the texture to the merged     |
  939.             |  object, since we run into too many difficulties if    |
  940.             |  we try to do this for them here.  There is a time     |
  941.             |  and a place for everything, and I think textures      |
  942.             |  don't belong here.                                    |
  943.             \-------------------------------------------------------*/
  944.  
  945.             /*----------------------------\         
  946.             |  Set up for next object.    |
  947.             \----------------------------*/
  948.             pstart = pstart + edesc->pcount;
  949.             estart = estart + edesc->ecount;
  950.             fstart = fstart + edesc->fcount;
  951.             extrcount++;
  952.             p = end;
  953.             end = end->next;
  954.  
  955.             /*--------------------------------------------------\           
  956.             |  And free object now that we are done with it.    |
  957.             \--------------------------------------------------*/
  958.             p->next = (struct OBJECT *)0;   /* Delete only this guy in chain */
  959.             p->parent = (struct OBJECT *)0;
  960.             free_object(p);
  961.          }       /* For all objects to merge */
  962.  
  963.          /*---------------------\
  964.          |  Free base object.   |
  965.          \---------------------*/
  966.          free_object(base);
  967.          
  968.          /*-------------------------\    
  969.          |  And return in glory.    |
  970.          \-------------------------*/
  971.          return(obj);
  972.  
  973. }    /* process_MXTR */
  974.  
  975. /*-------------------------------------------------------------------\
  976. |  Copy an object's attributes from one desc structure to another.   |
  977. |  What a pain.  But someone had to do it...                         |
  978. \-------------------------------------------------------------------*/
  979. static void desc_copy(edesc, desc)
  980. DESC *edesc, /* input desc structure */
  981.      *desc;  /* output desc structure */
  982. {     /* desc_copy */
  983.    if (edesc->name != '\0')
  984.       strcpy(desc->name, edesc->name);
  985.  
  986.    if (edesc->eflg)
  987.    {
  988.       if (!(desc->eflg = (EFLG*)malloc(sizeof(EFLG))))
  989.                         OUT_MEM("EFLG");
  990.       bcopy((char *)edesc->eflg, (char *)desc->eflg, sizeof(EFLG));
  991.       if (edesc->eflg->eflg)
  992.       {
  993.          if (!(desc->eflg->eflg = 
  994.               (UBYTE*)malloc(desc->eflg->num*sizeof(UBYTE))))
  995.                     OUT_MEM("EFLG");
  996.          bcopy((char *)edesc->eflg->eflg, (char *)edesc->eflg->eflg, 
  997.                edesc->eflg->num*sizeof(UBYTE));
  998.       }
  999.    }
  1000.                  
  1001.    if (edesc->shap)
  1002.    {
  1003.       if (!(desc->shap=(WORD*)malloc(2*sizeof(WORD))))
  1004.                                         { OUT_MEM("SHAP"); }
  1005.       bcopy((char *)edesc->shap, (char *)desc->shap, 2*sizeof(WORD));
  1006.    }
  1007.          
  1008.    if (edesc->posi)
  1009.    {
  1010.       if (!(desc->posi=(XYZ_st*)malloc(sizeof(XYZ_st))))
  1011.                                         { OUT_MEM("POSI"); }
  1012.       bcopy((char *)edesc->posi, (char *)desc->posi, sizeof(XYZ_st));
  1013.    }
  1014.  
  1015.    if (edesc->axis)
  1016.    {
  1017.       if (!(desc->axis=(AXIS*)malloc(sizeof(AXIS))))
  1018.                 { OUT_MEM("AXIS"); }
  1019.       bcopy((char *)edesc->axis, (char *)desc->axis, sizeof(AXIS));
  1020.    }
  1021.    
  1022.    if (edesc->size)
  1023.    {
  1024.       if (!(desc->size=(XYZ_st*)malloc(sizeof(XYZ_st))))
  1025.                         { OUT_MEM("SIZE"); }
  1026.       bcopy((char *)edesc->size, (char *)desc->size, sizeof(XYZ_st));
  1027.    }
  1028.  
  1029.    if (edesc->colr)
  1030.    {
  1031.       if (!(desc->colr = (RGB_st*)malloc(sizeof(RGB_st))))
  1032.                                         { OUT_MEM("COLR"); }
  1033.       bcopy((char *)edesc->colr, (char *)desc->colr, sizeof(RGB_st));
  1034.    }
  1035.    
  1036.    if (edesc->refl)
  1037.    {
  1038.       if (!(desc->refl = (RGB_st*)malloc(sizeof(RGB_st))))
  1039.                                         { OUT_MEM("REFL"); }
  1040.       bcopy((char *)edesc->refl, (char *)desc->refl, sizeof(RGB_st));
  1041.    }
  1042.  
  1043.    if (edesc->tran)
  1044.    {
  1045.       if (!(desc->tran = (RGB_st*)malloc(sizeof(RGB_st))))
  1046.                                         { OUT_MEM("TRAN"); }
  1047.       bcopy((char *)edesc->tran, (char *)desc->tran, sizeof(RGB_st));
  1048.    }
  1049.  
  1050.    if (edesc->spc1)
  1051.    {
  1052.       if (!(desc->spc1 = (RGB_st*)malloc(sizeof(RGB_st))))
  1053.                                         { OUT_MEM("SPC1"); }
  1054.       bcopy((char *)edesc->spc1, (char *)desc->spc1, sizeof(RGB_st));
  1055.    }
  1056.  
  1057.    if (edesc->tpar)
  1058.    {
  1059.       if (!(desc->tpar=(double*)malloc(16*sizeof(double))))
  1060.                                         { OUT_MEM("TPAR"); }
  1061.       bcopy((char *)edesc->tpar, (char *)desc->tpar, 16*sizeof(double));
  1062.    }
  1063.  
  1064.    if (edesc->surf)
  1065.    {
  1066.       if (!(desc->surf=(UBYTE*)malloc(5*sizeof(UBYTE))))
  1067.                                         { OUT_MEM("SURF"); }
  1068.       bcopy((char*)edesc->surf, (char *)desc->surf, 5*sizeof(UBYTE));
  1069.    }
  1070.  
  1071.    if (edesc->mttr)
  1072.    {
  1073.       if (!(desc->mttr=(MTTR*)malloc(sizeof(MTTR))))
  1074.                                         { OUT_MEM("MTTR"); }
  1075.       bcopy((char*)edesc->mttr, (char *)desc->mttr, sizeof(MTTR));
  1076.    }
  1077.    
  1078.    if (edesc->spec)
  1079.    {
  1080.       if (!(desc->spec=(UBYTE*)malloc(2*sizeof(UBYTE))))
  1081.                                         { OUT_MEM("SPEC"); }
  1082.       bcopy((char*)edesc->spec, (char *)desc->spec, 2*sizeof(UBYTE));
  1083.    }
  1084.  
  1085.    if (edesc->prp0)
  1086.    {
  1087.       if (!(desc->prp0=(UBYTE*)malloc(6*sizeof(UBYTE))))
  1088.                                         { OUT_MEM("PRP0"); }
  1089.       bcopy((char*)edesc->prp0, (char *)desc->prp0, 6*sizeof(UBYTE));
  1090.    }
  1091.  
  1092.    if (edesc->prp1)
  1093.    {
  1094.       if (!(desc->prp1=(UBYTE*)malloc(8*sizeof(UBYTE))))
  1095.                                         { OUT_MEM("PRP1"); }
  1096.       bcopy((char*)edesc->prp1, (char *)desc->prp1, 8*sizeof(UBYTE));
  1097.    }
  1098.  
  1099.    if (edesc->ints)
  1100.    {
  1101.       if (!(desc->ints=(double*)malloc(sizeof(double))))
  1102.                                         { OUT_MEM("INTS"); }
  1103.       bcopy((char *)edesc->ints, (char *)desc->ints, sizeof(double));
  1104.    }
  1105.    
  1106.    if (edesc->int1)
  1107.    {
  1108.       if (!(desc->int1=(XYZ_st*)malloc(sizeof(XYZ_st))))
  1109.                                    { OUT_MEM("INT1"); }
  1110.       bcopy((char *)edesc->int1, (char *)desc->int1, sizeof(XYZ_st));
  1111.    }
  1112. }     /* desc_copy */
  1113. /*----------------------\
  1114. |  That's all folks.    |
  1115. \----------------------*/
  1116.  
  1117. static OBJECT *process_EXTR(obj, world)
  1118. OBJECT *obj;
  1119. WORLD *world;
  1120. {
  1121.     register EXTR *extr;
  1122.     register OBJECT *p;
  1123.     char this_level[MAXLINE], name[5];
  1124.     MTRX *mtrx;
  1125.     WORLD *new;
  1126.     FILE *newinp;
  1127.  
  1128.     if (!(extr = obj->extr = (EXTR*)malloc(sizeof(EXTR)))) { OUT_MEM("EXTR"); }
  1129.     bzero((char*)extr, sizeof(EXTR));
  1130.     mtrx = &extr->mtrx;
  1131.     /* Initialize structure */
  1132.     mtrx->tran.x  = mtrx->tran.y  = mtrx->tran.z  = 0.0;
  1133.     mtrx->scal.x  = mtrx->scal.y  = mtrx->scal.z  = 1.0;
  1134.     mtrx->rota1.y = mtrx->rota1.z = 0.0;
  1135.     mtrx->rota2.x = mtrx->rota2.z = 0.0;
  1136.     mtrx->rota3.x = mtrx->rota3.y = 0.0;
  1137.     mtrx->rota1.x = mtrx->rota2.y = mtrx->rota3.z = 1.0;
  1138.  
  1139.     parse_word(this_level, 0, 1);    /* No limit, uppercase. */
  1140.     if (strcmp(this_level, "BEGIN") != 0) {
  1141.         fprintf(stderr, "WARNING: Line %d: Bad syntax.  Missing 'Begin' after 'EXTR'\n",
  1142.             world->cur_line);
  1143.     }
  1144.     parse_word(this_level, 0, 0);    /* No limit, original case */
  1145.  
  1146.     while (get_line(strin, world)) {
  1147.         parse_word(name, 4, 1);        /* Get command */
  1148.         if        (strcmp(name, "MTRX")==0) {
  1149.             parse_word(name, 4, 1);        /* Get field */
  1150.             if      (strcmp(name, "TRAN")==0) stuff_XYZ(&mtrx->tran);
  1151.             else if (strcmp(name, "SCAL")==0) stuff_XYZ(&mtrx->scal);
  1152.             else if (strcmp(name, "ROTA")==0) {
  1153.                 stuff_XYZ(&mtrx->rota1);
  1154.                 stuff_XYZ(&mtrx->rota2);
  1155.                 stuff_XYZ(&mtrx->rota3);
  1156.             } else {
  1157.                 if (verbose_flag)
  1158.                     fprintf(stderr, "WARNING: Line %d: Unknown MTRX field: '%s'\n",
  1159.                         world->cur_line, name);
  1160.                 continue;
  1161.             }
  1162.         } else if (strcmp(name, "LOAD")==0) {
  1163.             parse_word(extr->filename, 80, 0);
  1164.         } else if (strcmp(name, "END" )==0) {
  1165.             parse_word(name, 4, 1);
  1166.             if (strcmp(name, "EXTR")!=0)
  1167.                 fprintf(stderr, "WARNING: Line %d: Expected 'END EXTR' but got: 'END %s'\n", world->cur_line, name);
  1168.             parse_word(ps, 0, 0);    /* Get the quote, if any */
  1169.             if (strcmp(this_level, ps)!=0)
  1170.                 fprintf(stderr, "WARNING: Line %d: 'EXTR Begin' and 'End EXTR' quoted comments do not match\n", world->cur_line);
  1171.             break;
  1172.         } else if (verbose_flag)
  1173.             fprintf(stderr, "WARNING: Line %d: Unknown EXTR sub-sub-chunk: '%s'\n",
  1174.                 world->cur_line, name);
  1175.     }
  1176.     /* Now, load in the external object */
  1177.     if (!(newinp=fopen(extr->filename, "r"))) {
  1178.         fprintf(stderr, "Can't load in EXTR object: '%s'... ignored.\n",
  1179.             extr->filename);
  1180.         return(obj);
  1181.     }
  1182.     new = read_World(newinp);
  1183.     fclose(newinp);
  1184.     /* scale, rotate, and translate new object hierarchy */
  1185.     for (p=new->object; p; p=p->next)
  1186.         move_extr(p, mtrx);
  1187.     /* Free up unused memory */
  1188.     free((char*)obj->extr);
  1189.     free((char*)obj);
  1190.     obj = new->object;
  1191.     free((char*)new);
  1192.     return(obj);
  1193. }
  1194.  
  1195. void move_extr(obj, mtrx)
  1196. register OBJECT *obj;
  1197. register MTRX *mtrx;
  1198. {
  1199.     register XYZ_st *p;
  1200.     register int i;
  1201.     register double x, y, z;
  1202.     if (obj->desc) {
  1203.         if (obj->desc->posi) {
  1204.             obj->desc->posi->x += mtrx->tran.x;
  1205.             obj->desc->posi->y += mtrx->tran.y;
  1206.             obj->desc->posi->z += mtrx->tran.z;
  1207.         }
  1208.         for (p=obj->desc->pnts,i=obj->desc->pcount; i--; p++) {
  1209.             x = (p->x*mtrx->scal.x);
  1210.             y = (p->y*mtrx->scal.y);
  1211.             z = (p->z*mtrx->scal.z);
  1212.             p->x = x*mtrx->rota1.x +
  1213.                         y*mtrx->rota1.y +
  1214.                         z*mtrx->rota1.z +
  1215.                         mtrx->tran.x;
  1216.             p->y = x*mtrx->rota2.x +
  1217.                         y*mtrx->rota2.y +
  1218.                         z*mtrx->rota2.z +
  1219.                         mtrx->tran.y;
  1220.             p->z = x*mtrx->rota3.x +
  1221.                         y*mtrx->rota3.y +
  1222.                         z*mtrx->rota3.z +
  1223.                         mtrx->tran.z;
  1224.         }
  1225.         if (obj->desc->size) {
  1226.             obj->desc->size->x = mtrx->scal.x;
  1227.             obj->desc->size->y = mtrx->scal.y;
  1228.             obj->desc->size->z = mtrx->scal.z;
  1229.         }
  1230.     }
  1231.     for (obj=obj->child; obj; obj=obj->next)
  1232.         move_extr(obj, mtrx);    /* Process all children */
  1233. }
  1234.  
  1235. void OUT_MEM(s)
  1236. char *s;
  1237. {
  1238.     if (s)
  1239.     fprintf(stderr, "Ran out of memory while processing '%s'.  Sorry.\n", s);
  1240.     exit(-1);
  1241. }
  1242.  
  1243. static void malloc_arrays(i, desc)
  1244. register int i;
  1245. register DESC *desc;
  1246. {
  1247.     if (!desc->fcount) {
  1248.         desc->fcount = i;
  1249. if (!(desc->face=(UWORD*)malloc(3*desc->fcount*sizeof(UWORD))))OUT_MEM((char*)0);
  1250. if (!(desc->clst=(UBYTE*)malloc(3*desc->fcount*sizeof(UBYTE))))OUT_MEM((char*)0);
  1251. if (!(desc->rlst=(UBYTE*)malloc(3*desc->fcount*sizeof(UBYTE))))OUT_MEM((char*)0);
  1252. if (!(desc->tlst=(UBYTE*)malloc(3*desc->fcount*sizeof(UBYTE))))OUT_MEM((char*)0);
  1253.         /* Initialize arrays */
  1254.         for (i=0; i<3*desc->fcount; i+=3) {
  1255.             desc->face[i]   = desc->face[i+1] = desc->face[i+2] = 0;
  1256.             desc->clst[i]   = defclst[0];
  1257.             desc->clst[i+1] = defclst[1];
  1258.             desc->clst[i+2] = defclst[2];
  1259.             desc->rlst[i]   = defrlst[0];
  1260.             desc->rlst[i+1] = defrlst[1];
  1261.             desc->rlst[i+2] = defrlst[2];
  1262.             desc->tlst[i]   = deftlst[0];
  1263.             desc->tlst[i+1] = deftlst[1];
  1264.             desc->tlst[i+2] = deftlst[2];
  1265.         }
  1266.     } else if (i != desc->fcount) {
  1267.         fprintf(stderr, "ERROR: FACE and [C|R|T]LST 'Count' values inconsistant.\n");
  1268.         OUT_MEM((char*)0);
  1269.     }
  1270. }
  1271.  
  1272. static void process_DESC(orig, world)
  1273. DESC **orig;
  1274. WORLD *world;
  1275. {
  1276.     register DESC *desc;
  1277.     register int i, j;
  1278.     char this_level[MAXLINE], name[5];
  1279.     FGRP *fgrp;
  1280.  
  1281.     if (!(desc = *orig = (DESC*)malloc(sizeof(DESC)))) { OUT_MEM("DESC"); }
  1282.     bzero((char*)desc, sizeof(DESC));
  1283.  
  1284.     /* Set up defaults: */
  1285.     defclst[0] = defclst[1] = defclst[2] = 240;    /* TS default */
  1286.     defrlst[0] = defrlst[1] = defrlst[2] = 0;
  1287.     deftlst[0] = deftlst[1] = deftlst[2] = 0;
  1288.     defspc1[0] = defspc1[1] = defspc1[2] = 0;
  1289.  
  1290.     parse_word(this_level, 0, 1);    /* No limit, uppercase. */
  1291.     if (strcmp(this_level, "BEGIN") != 0) {
  1292.         fprintf(stderr, "WARNING: Line %d: Bad syntax.  Missing 'Begin' after 'DESC'\n",
  1293.             world->cur_line);
  1294.     }
  1295.     parse_word(this_level, 0, 0);    /* No limit, original case */
  1296.  
  1297.     world->num_DESC++;
  1298.  
  1299.     while (get_line(strin, world)) {
  1300.         parse_word(name, 4, 1);        /* Get command */
  1301.         /* Put most-frequent commands near the front of this list */
  1302.         if (strcmp(name, "PNTS")==0) {
  1303.             parse_word(name, 4, 1);        /* Get field */
  1304.             if          (strcmp(name, "POIN")==0) {
  1305.                 if (!desc->pcount) {
  1306.                     fprintf(stderr, "ERROR: Line %d: 'PNTS Point' encountered before 'PNTS PCount'\n", world->cur_line);
  1307.                     OUT_MEM((char*)0);
  1308.                 }
  1309.                 i = get_UWORD();
  1310.                 if (i<0 || i>=desc->pcount) {
  1311.                     fprintf(stderr, "WARNING: Line %d: Bad index: PNTS Point[%d] should be [0..%d]\n", world->cur_line, i, desc->pcount-1);
  1312.                     continue;
  1313.                 }
  1314.                 stuff_XYZ(&desc->pnts[i]);
  1315.             } else if (strcmp(name, "PCOU")==0) {
  1316.                 if (!desc->pcount) {
  1317.                     desc->pcount = get_UWORD();
  1318.                     if (!(desc->pnts = (XYZ_st*)malloc(desc->pcount*sizeof(XYZ_st))))
  1319.                         OUT_MEM("PNTS");
  1320.                     /* Initialize array */
  1321.                     for (i=0; i<desc->pcount; i++) {
  1322.                         desc->pnts[i].x = 0;
  1323.                         desc->pnts[i].y = 0;
  1324.                         desc->pnts[i].z = 0;
  1325.                     }
  1326.                 } else {
  1327.                     fprintf(stderr, "WARNING: Line %d: PNTS Pcount defined more than once.\n", world->cur_line);
  1328.                 }
  1329.             } else {
  1330.                 if (verbose_flag)
  1331.                     fprintf(stderr, "WARNING: Line %d: Unknown PNTS field: '%s'\n",
  1332.                         world->cur_line, name);
  1333.                 continue;
  1334.             }
  1335.         } else
  1336.         if (strcmp(name, "EDGE")==0) {
  1337.             parse_word(name, 4, 1);        /* Get field */
  1338.             if          (strcmp(name, "EDGE")==0) {
  1339.                 if (!desc->ecount) {
  1340.                     fprintf(stderr, "ERROR: Line %d: 'EDGE Edge' encountered before 'EDGE ECount'\n", world->cur_line);
  1341.                     OUT_MEM((char*)0);
  1342.                 }
  1343.                 i = get_UWORD();
  1344.                 if (i<0 || i>=desc->ecount) {
  1345.                     fprintf(stderr, "WARNING: Line %d: Bad index: EDGE Edge[%d] should be [0..%d]\n", world->cur_line, i, desc->ecount-1);
  1346.                     continue;
  1347.                 }
  1348.                 desc->edge[2*i]   = get_UWORD();
  1349.                 desc->edge[2*i+1] = get_UWORD();
  1350.             } else if (strcmp(name, "ECOU")==0) {
  1351.                 if (!desc->ecount) {
  1352.                     desc->ecount = get_UWORD();
  1353.                     if (!(desc->edge = (UWORD*)malloc(2*desc->ecount*sizeof(UWORD))))
  1354.                         OUT_MEM("EDGE");
  1355.                     /* Initialize array */
  1356.                     for (i=0; i<2*desc->ecount; i++)
  1357.                         desc->edge[i] = 0;
  1358.                 } else {
  1359.                     fprintf(stderr, "WARNING: Line %d: EDGE Ecount defined more than once.\n", world->cur_line);
  1360.                 }
  1361.             } else {
  1362.                 if (verbose_flag)
  1363.                     fprintf(stderr, "WARNING: Line %d: Unknown EDGE field: '%s'\n",
  1364.                         world->cur_line, name);
  1365.                 continue;
  1366.             }
  1367.         } else
  1368.         if (strcmp(name, "EFLG")==0) {
  1369.             parse_word(name, 4, 1);        /* Get field */
  1370.             if (strcmp(name, "COUN")==0) {
  1371.                 if (!desc->eflg) {
  1372.                     if (!(desc->eflg = (EFLG*)malloc(sizeof(EFLG))))
  1373.                         OUT_MEM("EFLG");
  1374.                     desc->eflg->num = get_UWORD();
  1375.                     if (!(desc->eflg->eflg = (UBYTE*)malloc(desc->eflg->num*sizeof(UBYTE))))
  1376.                         OUT_MEM("EFLG");
  1377.                     /* Initialize array */
  1378.                     for (i=0; i<desc->eflg->num; i++)
  1379.                         desc->eflg->eflg[i] = 0;
  1380.                 } else {
  1381.                     fprintf(stderr, "WARNING: Line %d: EFLG Count defined more than once.\n", world->cur_line);
  1382.                 }
  1383.             } else if (strcmp(name, "EFLG")==0) {
  1384.                 if (!desc->eflg) {
  1385.                     fprintf(stderr, "ERROR: Line %d: 'EFLG Eflg' encountered before 'EFLG Count'\n", world->cur_line);
  1386.                     OUT_MEM((char*)0);
  1387.                 }
  1388.                 i = get_UWORD();
  1389.                 if (i<0 || i>=desc->eflg->num) {
  1390.                     fprintf(stderr, "WARNING: Line %d: Bad index: EFLG Eflg[%d] should be [0..%d]\n", world->cur_line, i, desc->eflg->num-1);
  1391.                     continue;
  1392.                 }
  1393.                 desc->eflg->eflg[i]   = get_UWORD();
  1394.             } else {
  1395.                 if (verbose_flag)
  1396.                     fprintf(stderr, "WARNING: Line %d: Unknown EFLG field: '%s'\n",
  1397.                         world->cur_line, name);
  1398.                 continue;
  1399.             }
  1400.         } else
  1401.         if (strcmp(name, "FACE")==0) {
  1402.             parse_word(name, 4, 1);        /* Get field */
  1403.             if          (strcmp(name, "CONN")==0) {
  1404.                 if (!desc->fcount) {
  1405.                     fprintf(stderr, "ERROR: Line %d: 'FACE Connects' encountered before 'FACE TCount'\n", world->cur_line);
  1406.                     OUT_MEM((char*)0);
  1407.                 }
  1408.                 i = get_UWORD();
  1409.                 if (i<0 || i>=desc->fcount) {
  1410.                     fprintf(stderr, "WARNING: Line %d: Bad index: FACE Connects[%d] should be [0..%d]\n", world->cur_line, i, desc->fcount-1);
  1411.                     continue;
  1412.                 }
  1413.                 desc->face[3*i]   = get_UWORD();
  1414.                 desc->face[3*i+1] = get_UWORD();
  1415.                 desc->face[3*i+2] = get_UWORD();
  1416.             } else if (strcmp(name, "TCOU")==0) {
  1417.                 i = get_UWORD();
  1418.                 malloc_arrays(i, desc);
  1419.             } else {
  1420.                 if (verbose_flag)
  1421.                     fprintf(stderr, "WARNING: Line %d: Unknown FACE field: '%s'\n",
  1422.                         world->cur_line, name);
  1423.                 continue;
  1424.             }
  1425.         } else
  1426.         if (strcmp(name, "FGRP")==0) {
  1427.             parse_word(name, 4, 1);
  1428.             if (strcmp(name, "NAME")==0) {
  1429.                 if (!(fgrp = (FGRP*)malloc(sizeof(FGRP))))
  1430.                     OUT_MEM("FGRP");
  1431.                 bzero((char*)fgrp, sizeof(FGRP));
  1432.                 parse_word(ps, 0, 0);
  1433.                 strncpy(fgrp->name, ps, 18);
  1434.                 fgrp->name[18]='\0';
  1435.                 fgrp->next = desc->fgrp;
  1436.                 desc->fgrp = fgrp;
  1437.             } else if (strcmp(name, "COUN")==0) {
  1438.                 i = get_UWORD();
  1439.                 if (!desc->fgrp) {
  1440.                     fprintf(stderr, "ERROR: Line %d: 'FGRP Count' encountered before 'FGRP Name'\n", world->cur_line);
  1441.                     OUT_MEM((char*)0);
  1442.                 }
  1443.                 if (desc->fgrp->face) {
  1444.                     fprintf(stderr, "ERROR: Line %d: 'FGRP Count' encountered twice\n", world->cur_line);
  1445.                     OUT_MEM((char*)0);
  1446.                 }
  1447.                 desc->fgrp->num = i;
  1448.                 if (!(desc->fgrp->face = (UWORD*)malloc(i*sizeof(UWORD))))
  1449.                     OUT_MEM("FGRP");
  1450.                 while (i--) desc->fgrp->face[i] = 0;
  1451.             } else if (strcmp(name, "FACE")==0) {
  1452.                 i = get_UWORD();
  1453.                 if (i<0 || i>=desc->fgrp->num) {
  1454.                     fprintf(stderr, "WARNING: Line %d: Bad index: FGRP Face[%d] should be [0..%d]\n", world->cur_line, i, desc->fgrp->num-1);
  1455.                     continue;
  1456.                 }
  1457.                 desc->fgrp->face[i] = get_UWORD();
  1458.             } else {
  1459.                 if (verbose_flag)
  1460.                     fprintf(stderr, "WARNING: Line %d: Unknown FGRP field: '%s'\n",
  1461.                         world->cur_line, name);
  1462.                 continue;
  1463.             }
  1464.         } else
  1465.         if (strcmp(name, "CLST")==0) {
  1466.             parse_word(name, 4, 1);        /* Get field */
  1467.             if          (strcmp(name, "COLO")==0) {
  1468.                 if (!desc->fcount) {
  1469.                     fprintf(stderr, "ERROR: Line %d: 'CLST Color' encountered before 'CLST Count'\n", world->cur_line);
  1470.                     OUT_MEM((char*)0);
  1471.                 }
  1472.                 i = get_UWORD();
  1473.                 if (i<0 || i>=desc->fcount) {
  1474.                     fprintf(stderr, "WARNING: Line %d: Bad index: CLST Color[%d] should be [0..%d]\n", world->cur_line, i, desc->fcount-1);
  1475.                     continue;
  1476.                 }
  1477.                 stuff_RGB((RGB_st*)&desc->clst[3*i]);    /* Place 3 UBYTE's into array */
  1478.             } else if (strcmp(name, "COUN")==0) {
  1479.                 i = get_UWORD();
  1480.                 malloc_arrays(i, desc);
  1481.             } else {
  1482.                 if (verbose_flag)
  1483.                     fprintf(stderr, "WARNING: Line %d: Unknown CLST field: '%s'\n",
  1484.                         world->cur_line, name);
  1485.                 continue;
  1486.             }
  1487.         } else
  1488.         if (strcmp(name, "RLST")==0) {
  1489.             parse_word(name, 4, 1);        /* Get field */
  1490.             if          (strcmp(name, "COLO")==0) {
  1491.                 if (!desc->fcount) {
  1492.                     fprintf(stderr, "ERROR: Line %d: 'RLST Color' encountered before 'RLST Count'\n", world->cur_line);
  1493.                     OUT_MEM((char*)0);
  1494.                 }
  1495.                 i = get_UWORD();
  1496.                 if (i<0 || i>=desc->fcount) {
  1497.                     fprintf(stderr, "WARNING: Line %d: Bad index: RLST Color[%d] should be [0..%d]\n", world->cur_line, i, desc->fcount-1);
  1498.                     continue;
  1499.                 }
  1500.                 stuff_RGB((RGB_st*)&desc->rlst[3*i]);    /* Place three UBYTE's into array */
  1501.             } else if (strcmp(name, "COUN")==0) {
  1502.                 i = get_UWORD();
  1503.                 malloc_arrays(i, desc);
  1504.             } else {
  1505.                 if (verbose_flag)
  1506.                     fprintf(stderr, "WARNING: Line %d: Unknown RLST field: '%s'\n",
  1507.                         world->cur_line, name);
  1508.                 continue;
  1509.             }
  1510.         } else
  1511.         if (strcmp(name, "TLST")==0) {
  1512.             parse_word(name, 4, 1);        /* Get field */
  1513.             if          (strcmp(name, "COLO")==0) {
  1514.                 if (!desc->fcount) {
  1515.                     fprintf(stderr, "ERROR: Line %d: 'TLST Color' encountered before 'TLST Count'\n", world->cur_line);
  1516.                     OUT_MEM((char*)0);
  1517.                 }
  1518.                 i = get_UWORD();
  1519.                 if (i<0 || i>=desc->fcount) {
  1520.                     fprintf(stderr, "WARNING: Line %d: Bad index: TLST Color[%d] should be [0..%d]\n", world->cur_line, i, desc->fcount-1);
  1521.                     continue;
  1522.                 }
  1523.                 stuff_RGB((RGB_st*)&desc->tlst[3*i]);    /* Place three UBYTE's into array */
  1524.             } else if (strcmp(name, "COUN")==0) {
  1525.                 i = get_UWORD();
  1526.                 malloc_arrays(i, desc);
  1527.             } else {
  1528.                 if (verbose_flag)
  1529.                     fprintf(stderr, "WARNING: Line %d: Unknown TLST field: '%s'\n",
  1530.                         world->cur_line, name);
  1531.                 continue;
  1532.             }
  1533.         } else
  1534.         if (strcmp(name, "NAME")==0) {
  1535.             parse_word(ps, 0, 0);
  1536.             strncpy(desc->name, ps, 18);
  1537.             desc->name[18]='\0';
  1538.         } else
  1539.         if (strcmp(name, "SHAP")==0) {
  1540.             if (!desc->shap) {
  1541.                 if (!(desc->shap=(WORD*)malloc(2*sizeof(WORD))))
  1542.                     { OUT_MEM("SHAP"); }
  1543.                 desc->shap[0] = 2;    /* TS defaults */
  1544.                 desc->shap[1] = 0;
  1545.             }
  1546.             parse_word(name, 4, 1);        /* Get field */
  1547.             if        (strcmp(name, "SHAP")==0) desc->shap[0] = get_UWORD();
  1548.             else if (strcmp(name, "LAMP")==0) desc->shap[1] = get_UWORD();
  1549.             else {
  1550.                 if (verbose_flag)
  1551.                     fprintf(stderr, "WARNING: Line %d: Unknown SHAP field: '%s'\n",
  1552.                         world->cur_line, name);
  1553.                 continue;
  1554.             }
  1555.         } else
  1556.         if (strcmp(name, "POSI")==0) {
  1557.             if (!desc->posi) {
  1558.                 if (!(desc->posi=(XYZ_st*)malloc(sizeof(XYZ_st))))
  1559.                     { OUT_MEM("POSI"); }
  1560.             }
  1561.             stuff_XYZ(desc->posi);
  1562.         } else
  1563.         if (strcmp(name, "AXIS")==0) {
  1564.             if (!desc->axis) {
  1565.                 if (!(desc->axis=(AXIS*)malloc(sizeof(AXIS))))
  1566.                     { OUT_MEM("AXIS"); }
  1567.                 bzero((char*)desc->axis, sizeof(AXIS));
  1568.                 desc->axis->xaxi.x = 1;
  1569.                 desc->axis->yaxi.y = 1;
  1570.                 desc->axis->zaxi.z = 1;
  1571.             }
  1572.             parse_word(name, 4, 1);        /* Get field */
  1573.             if        (strcmp(name, "XAXI")==0) stuff_XYZ(&desc->axis->xaxi);
  1574.             else if (strcmp(name, "YAXI")==0) stuff_XYZ(&desc->axis->yaxi);
  1575.             else if (strcmp(name, "ZAXI")==0) stuff_XYZ(&desc->axis->zaxi);
  1576.             else {
  1577.                 if (verbose_flag)
  1578.                     fprintf(stderr, "WARNING: Line %d: Unknown AXIS field: '%s'\n",
  1579.                         world->cur_line, name);
  1580.                 continue;
  1581.             }
  1582.         } else
  1583.         if (strcmp(name, "SIZE")==0) {
  1584.             if (!desc->size) {
  1585.                 if (!(desc->size=(XYZ_st*)malloc(sizeof(XYZ_st))))
  1586.                     { OUT_MEM("SIZE"); }
  1587.             }
  1588.             stuff_XYZ(desc->size);
  1589.         } else
  1590.         if (strcmp(name, "COLR")==0) {
  1591.             if (!desc->colr) {
  1592.                 if (!(desc->colr = (RGB_st*)malloc(sizeof(RGB_st))))
  1593.                     { OUT_MEM("COLR"); }
  1594.             }
  1595.             stuff_RGB((RGB_st*)&defclst[0]);
  1596.             desc->colr->r = defclst[0];
  1597.             desc->colr->g = defclst[1];
  1598.             desc->colr->b = defclst[2];
  1599. #ifdef DO_I_REALLY_WANT_TO_DO_THIS
  1600.             if (desc->fcount) {    /* Already initialized... rewrite */
  1601.                 for (i=3*desc->fcount; i; ) {        /* Reverse - efficiency */
  1602.                     desc->clst[--i] = defclst[2];
  1603.                     desc->clst[--i] = defclst[1];
  1604.                     desc->clst[--i] = defclst[0];
  1605.                 }
  1606.             }
  1607. #endif
  1608.         } else
  1609.         if (strcmp(name, "REFL")==0) {
  1610.             if (!desc->refl) {
  1611.                 if (!(desc->refl = (RGB_st*)malloc(sizeof(RGB_st))))
  1612.                     { OUT_MEM("REFL"); }
  1613.             }
  1614.             stuff_RGB((RGB_st*)&defrlst[0]);
  1615.             desc->refl->r = defrlst[0];
  1616.             desc->refl->g = defrlst[1];
  1617.             desc->refl->b = defrlst[2];
  1618. #ifdef DO_I_REALLY_WANT_TO_DO_THIS
  1619.             if (desc->fcount) {    /* Already initialized... rewrite */
  1620.                 for (i=3*desc->fcount; i; ) {        /* Reverse - efficiency */
  1621.                     desc->rlst[--i] = defrlst[2];
  1622.                     desc->rlst[--i] = defrlst[1];
  1623.                     desc->rlst[--i] = defrlst[0];
  1624.                 }
  1625.             }
  1626. #endif
  1627.         } else
  1628.         if (strcmp(name, "TRAN")==0) {
  1629.             if (!desc->tran) {
  1630.                 if (!(desc->tran = (RGB_st*)malloc(sizeof(RGB_st))))
  1631.                     { OUT_MEM("TRAN"); }
  1632.             }
  1633.             stuff_RGB((RGB_st*)&deftlst[0]);
  1634.             desc->tran->r = deftlst[0];
  1635.             desc->tran->g = deftlst[1];
  1636.             desc->tran->b = deftlst[2];
  1637. #ifdef DO_I_REALLY_WANT_TO_DO_THIS
  1638.             if (desc->fcount) {    /* Already initialized... rewrite */
  1639.                 for (i=3*desc->fcount; i; ) {        /* Reverse - efficiency */
  1640.                     desc->tlst[--i] = deftlst[2];
  1641.                     desc->tlst[--i] = deftlst[1];
  1642.                     desc->tlst[--i] = deftlst[0];
  1643.                 }
  1644.             }
  1645. #endif
  1646.         } else
  1647.         if (strcmp(name, "SPC1")==0) {
  1648.             if (!desc->spc1) {
  1649.                 if (!(desc->spc1 = (RGB_st*)malloc(sizeof(RGB_st))))
  1650.                     { OUT_MEM("SPC1"); }
  1651.             }
  1652.             stuff_RGB((RGB_st*)&defspc1[0]);
  1653.             desc->spc1->r = defspc1[0];
  1654.             desc->spc1->g = defspc1[1];
  1655.             desc->spc1->b = defspc1[2];
  1656.         } else
  1657.         if (strcmp(name, "TPAR")==0) {
  1658.             if (!desc->tpar) {
  1659.                 if (!(desc->tpar=(double*)malloc(16*sizeof(double))))
  1660.                     { OUT_MEM("TPAR"); }
  1661.                 bzero((char*)desc->tpar, 16*sizeof(double));
  1662.             }
  1663.             i = get_UWORD();
  1664.             if (i<0 || i>15) {
  1665.                 fprintf(stderr, "WARNING: Line %d: Bad index: TPAR[%d] should be [0..15]\n", world->cur_line, i);
  1666.                 continue;
  1667.             }
  1668.             desc->tpar[i] = get_FRACT();
  1669.         } else
  1670.         if (strcmp(name, "SURF")==0) {
  1671.             if (!desc->surf) {
  1672.                 if (!(desc->surf=(UBYTE*)malloc(5*sizeof(UBYTE))))
  1673.                     { OUT_MEM("SURF"); }
  1674.                 bzero((char*)desc->surf, 5*sizeof(UBYTE));
  1675.             }
  1676.             i = get_UWORD();
  1677.             if (i<0 || i>4) {
  1678.                 fprintf(stderr, "WARNING: Line %d: Bad index: SURF[%d] should be [0..4]\n", world->cur_line, i);
  1679.                 continue;
  1680.             }
  1681.             desc->surf[i] = get_UBYTE();
  1682.         } else
  1683.         if (strcmp(name, "MTTR")==0) {
  1684.             if (!desc->mttr) {
  1685.                 if (!(desc->mttr=(MTTR*)malloc(sizeof(MTTR))))
  1686.                     { OUT_MEM("MTTR"); }
  1687.                 bzero((char*)desc->mttr, sizeof(MTTR));
  1688.             }
  1689.             parse_word(name, 4, 1);        /* Get field */
  1690.             if        (strcmp(name, "TYPE")==0) {
  1691.                 desc->mttr->type = get_UBYTE();
  1692.                 if (desc->mttr->type>4) {
  1693.                     fprintf(stderr, "WARNING: Line %d: Invalid MTTR refraction Type %d.  Must be [0..4]\n", world->cur_line, desc->mttr->type);
  1694.                     desc->mttr->type = 0;
  1695.                     continue;
  1696.                 }
  1697.             } else if (strcmp(name, "INDE")==0) {    /* Must be between 1.0 and 3.55 inclusive */
  1698.                 desc->mttr->indx = get_FRACT();
  1699.                 if (desc->mttr->indx<1.0 || desc->mttr->indx>3.55) {
  1700.                     fprintf(stderr, "WARNING: Line %d: Invalid MTTR Index of refraction.  Must be (1.0 - 3.55)\n", world->cur_line);
  1701.                     desc->mttr->indx = 1.0;
  1702.                     continue;
  1703.                 }
  1704.             } else {
  1705.                 if (verbose_flag)
  1706.                     fprintf(stderr, "WARNING: Line %d: Unknown MTTR field: '%s'\n",
  1707.                         world->cur_line, name);
  1708.                 continue;
  1709.             }
  1710.         } else
  1711.         if (strcmp(name, "SPEC")==0) {
  1712.             if (!desc->spec) {
  1713.                 if (!(desc->spec=(UBYTE*)malloc(2*sizeof(UBYTE))))
  1714.                     { OUT_MEM("SPEC"); }
  1715.                 bzero((char*)desc->spec, 2*sizeof(UBYTE));
  1716.             }
  1717.             parse_word(name, 4, 1);        /* Get field */
  1718.             if        (strcmp(name, "SPEC")==0) desc->spec[0] = get_UBYTE();
  1719.             else if (strcmp(name, "HARD")==0) desc->spec[1] = get_UBYTE();
  1720.             else {
  1721.                 if (verbose_flag)
  1722.                     fprintf(stderr, "WARNING: Line %d: Unknown SPEC field: '%s'\n",
  1723.                         world->cur_line, name);
  1724.                 continue;
  1725.             }
  1726.         } else
  1727.         if (strcmp(name, "PRP0")==0) {
  1728.             if (!desc->prp0) {
  1729.                 if (!(desc->prp0=(UBYTE*)malloc(6*sizeof(UBYTE))))
  1730.                     { OUT_MEM("PRP0"); }
  1731.                 bzero((char*)desc->prp0, 6*sizeof(UBYTE));
  1732.                 desc->prp0[0] = 255;    /* TS defaults */
  1733.                 desc->prp0[3] = 1;
  1734.             }
  1735.             i = get_UWORD();
  1736.             if (i<0 || i>5) {
  1737.                 fprintf(stderr, "WARNING: Line %d: Bad index: PRP0[%d] should be [0..5]\n", world->cur_line, i);
  1738.                 continue;
  1739.             }
  1740.             desc->prp0[i] = get_UBYTE();
  1741.         } else
  1742.         if (strcmp(name, "PRP1")==0) {
  1743.             if (!desc->prp1) {
  1744.                 if (!(desc->prp1=(UBYTE*)malloc(8*sizeof(UBYTE))))
  1745.                     { OUT_MEM("PRP1"); }
  1746.                 bzero((char*)desc->prp1, 8*sizeof(UBYTE));
  1747.             }
  1748.             i = get_UWORD();
  1749.             if (i<0 || i>7) {
  1750.                 fprintf(stderr, "WARNING: Line %d: Bad index: PRP1[%d] should be [0..7]\n", world->cur_line, i);
  1751.                 continue;
  1752.             }
  1753.             desc->prp1[i] = get_UBYTE();
  1754.         } else
  1755.         if (strcmp(name, "TXT2")==0) {
  1756.             i = get_UWORD();
  1757.             if (i<0 || i>3) {
  1758.                 fprintf(stderr, "WARNING: Line %d: TXT2 index must be [0..3].\n",
  1759.                     world->cur_line);
  1760.                 i=3;
  1761.             }
  1762.             if (!desc->txt2[i])
  1763.                 if (!(desc->txt2[i] = (TXT2*)malloc(sizeof(TXT2))))
  1764.                     OUT_MEM("TXT2");
  1765.             parse_word(name, 4, 1);  /* get field */
  1766.             if (strcmp(name, "FLAG") == 0)
  1767.                 desc->txt2[i]->Flags = get_UWORD();
  1768.             else if (strcmp(name, "TRAN") == 0) 
  1769.                 stuff_XYZ(&desc->txt2[i]->TAxis.tran);
  1770.             else if (strcmp(name, "XAXI") == 0) 
  1771.                 stuff_XYZ(&desc->txt2[i]->TAxis.rota1);
  1772.             else if (strcmp(name, "YAXI") == 0) 
  1773.                 stuff_XYZ(&desc->txt2[i]->TAxis.rota2);
  1774.             else if (strcmp(name, "ZAXI") == 0) 
  1775.                 stuff_XYZ(&desc->txt2[i]->TAxis.rota3);
  1776.             else if (strcmp(name, "SCAL") == 0) 
  1777.                 stuff_XYZ(&desc->txt2[i]->TAxis.scal);
  1778.             else if (strcmp(name, "PARA") == 0) {
  1779.                 j = get_UWORD();
  1780.                 desc->txt2[i]->Params[j] = get_FRACT();
  1781.             } else if (strcmp(name, "PFLA") == 0) {
  1782.                 j = get_UWORD();
  1783.                 desc->txt2[i]->PFlags[j] = get_UWORD();
  1784.             } else if (strcmp(name, "SUBG") == 0) {
  1785.                 parse_word(ps, 0, 0);
  1786.                 strncpy(desc->txt2[i]->SubName, ps, 18);
  1787.                 desc->txt2[i]->SubName[18]='\0';
  1788.             } else if (strcmp(name, "TEXT") == 0)
  1789.                 parse_word(desc->txt2[i]->Name,0,0);
  1790.             else {
  1791. #ifdef WARNING
  1792.                 fprintf(stderr, "WARNING: Line %d: Unknown TXT2 field: '%s'\n",
  1793.                     world->cur_line, name);
  1794. #endif
  1795.                 continue;
  1796.             }
  1797.         } else
  1798.         if (strcmp(name, "INTS")==0) {
  1799.             if (!desc->ints) {
  1800.                 if (!(desc->ints=(double*)malloc(sizeof(double))))
  1801.                     { OUT_MEM("INTS"); }
  1802.             }
  1803.             *desc->ints = get_FRACT();
  1804.         } else
  1805.         if (strcmp(name, "INT1")==0) {
  1806.             if (!desc->int1) desc->int1=(XYZ_st*)malloc(sizeof(XYZ_st));
  1807.             if (!desc->int1) { OUT_MEM("INT1"); }
  1808.             stuff_XYZ(desc->int1);
  1809.         } else
  1810.         if (strcmp(name, "STRY")==0) {
  1811.             parse_word(name, 4, 1);        /* Get field */
  1812.             if        (strcmp(name, "PATH")==0) parse_word(desc->stry->path,18,0);
  1813.             else if (strcmp(name, "TRAN")==0) stuff_XYZ(&desc->stry->tran);
  1814.             else if (strcmp(name, "ROTA")==0) stuff_XYZ(&desc->stry->rota);
  1815.             else if (strcmp(name, "SCAL")==0) stuff_XYZ(&desc->stry->scal);
  1816.             else
  1817.             if (strcmp(name, "INFO")==0) {
  1818.                 desc->stry->info = 0;
  1819.                 while (strin[0]) {
  1820.                     parse_word(ps, 7, 1);
  1821.                     if        (strcmp(ps, "ABS_TRA")==0) desc->stry->info|=(1<<0);
  1822.                     else if (strcmp(ps, "ABS_ROT")==0) desc->stry->info|=(1<<1);
  1823.                     else if (strcmp(ps, "ABS_SCL")==0) desc->stry->info|=(1<<2);
  1824.                     else if (strcmp(ps, "LOC_TRA")==0) desc->stry->info|=(1<<4);
  1825.                     else if (strcmp(ps, "LOC_ROT")==0) desc->stry->info|=(1<<5);
  1826.                     else if (strcmp(ps, "LOC_SCL")==0) desc->stry->info|=(1<<6);
  1827.                     else if (strcmp(ps, "X_ALIGN")==0) desc->stry->info|=(1<<8);
  1828.                     else if (strcmp(ps, "Y_ALIGN")==0) desc->stry->info|=(1<<9);
  1829.                     else if (strcmp(ps, "Z_ALIGN")==0) desc->stry->info|=(1<<10);
  1830.                     else if (strcmp(ps, "FOLLOW_")==0) desc->stry->info|=(1<<12);
  1831.                     else {
  1832.                         if (verbose_flag)
  1833.                             fprintf(stderr, "WARNING: Line %d: Unknown STRY INFO flag: '%s'\n",
  1834.                                 world->cur_line, ps);
  1835.                         continue;
  1836.                     }
  1837.                 }
  1838.             } else {
  1839.                 if (verbose_flag)
  1840.                     fprintf(stderr, "WARNING: Line %d: Unknown STRY field: '%s'\n",
  1841.                         world->cur_line, name);
  1842.                 continue;
  1843.             }
  1844.         } else
  1845.         if (strcmp(name, "END")==0) {
  1846.             parse_word(name, 4, 1);
  1847.             if (strcmp(name, "DESC")!=0)
  1848.                 fprintf(stderr, "WARNING: Line %d: Expected 'END DESC' but got: 'END %s'\n", world->cur_line, name);
  1849.             parse_word(ps, 0, 0);    /* Get the quote, if any */
  1850.             if (strcmp(this_level, ps)!=0)
  1851.                 fprintf(stderr, "WARNING: Line %d: 'DESC Begin' and 'End DESC' quoted comments do not match\n", world->cur_line);
  1852.             break;
  1853.         } else if (verbose_flag)
  1854.             fprintf(stderr, "WARNING: Line %d: Unknown DESC sub-sub-chunk: '%s'\n",
  1855.                 world->cur_line, name);
  1856.     }
  1857. }
  1858.  
  1859. /**************************************************************************/
  1860.  
  1861. /* readTistg.c - read a Textual Imagine Stage file
  1862.  *            - written by Glenn M. Lewis - 8/11/92
  1863.  */
  1864.  
  1865. static void process_OSIZ();
  1866. static void process_POSN();
  1867. static void process_ALGN();
  1868. static void process_PALN();
  1869. static void process_TALN();
  1870. static void process_HING();
  1871. static void process_PTH2();
  1872. static void process_GLB2();
  1873. static void process_AXIS();
  1874. static void process_LITE();
  1875. static void process_FILE();
  1876. static void process_SOBJ();
  1877.  
  1878. static void process_ISTG(world)
  1879. WORLD *world;
  1880. {
  1881.     char name[5];
  1882.     char this_level[MAXLINE];
  1883.  
  1884.     if (world->istg) {
  1885.         fprintf(stderr, "Parse error: More than one ISTG chunk!\n"); exit(-1); }
  1886.     /* Allocate the ISTG structure */
  1887.     if (!(world->istg = (ISTG*)malloc(sizeof(ISTG)))) { OUT_MEM("ISTG"); }
  1888.     bzero((char*)world->istg, sizeof(ISTG));
  1889.  
  1890.     parse_word(this_level, 0, 1);    /* No limit, uppercase. */
  1891.     if (strcmp(this_level, "BEGIN") != 0) {
  1892.         fprintf(stderr, "WARNING: Line %d: Bad syntax.  Missing 'Begin' after 'ISTG'\n",
  1893.             world->cur_line);
  1894.     }
  1895.     parse_word(this_level, 0, 0);    /* No limit, original case */
  1896.  
  1897.     while (get_line(strin, world)) {
  1898.         parse_word(name, 4, 1);        /* Get command */
  1899.         if (strcmp(name, "MAXF")==0) {
  1900.             world->istg->maxf = get_UWORD();
  1901.         } else
  1902.         if (strcmp(name, "SOBJ")==0) {    process_SOBJ(world);
  1903.         } else if (strcmp(name, "END")==0) {
  1904.             parse_word(name, 4, 1);
  1905.             if (strcmp(name, "ISTG")!=0)
  1906.                 fprintf(stderr, "WARNING: Line %d: Expected 'END ISTG' but got: 'END %s'\n", world->cur_line, name);
  1907.             parse_word(ps, 0, 0);    /* Get the quote, if any */
  1908.             if (strcmp(this_level, ps)!=0)
  1909.                 fprintf(stderr, "WARNING: Line %d: 'ISTG Begin' and 'End ISTG' quoted comments do not match\n", world->cur_line);
  1910.             break;
  1911.         } else {
  1912.             if (verbose_flag)
  1913.                 fprintf(stderr, "WARNING: Line %d: Unknown ISTG sub-sub-chunk: '%s'\n",
  1914.                     world->cur_line, name);
  1915.             continue;
  1916.         }
  1917.     }
  1918. /* All done. */
  1919. }
  1920.  
  1921. extern SOBJ *add_SOBJ();    /* to tail of ISTG's SOBJ list */
  1922.  
  1923. static void process_SOBJ(world)
  1924. WORLD *world;
  1925. {
  1926.     char this_level[MAXLINE], name[5];
  1927.     SOBJ *sobj;
  1928.  
  1929.     if (verbose_flag>1) fprintf(stderr, "SOBJ chunk.\n");
  1930.     parse_word(this_level, 0, 1);    /* No limit, uppercase. */
  1931.     if (strcmp(this_level, "BEGIN") != 0) {
  1932.         fprintf(stderr, "WARNING: Line %d: Bad syntax.  Missing 'Begin' after 'SOBJ'\n",
  1933.             world->cur_line);
  1934.     }
  1935.     /* Add another SOBJ to the current ISTG list */
  1936.     parse_word(this_level, 0, 0);
  1937.     sobj = add_SOBJ(world->istg);
  1938.     while (get_line(strin, world)) {
  1939.         parse_word(name, 4, 1);
  1940.         if (verbose_flag>1) fprintf(stderr, "%s chunk.\n", name);
  1941.         if (strcmp(name, "NAME")==0) {
  1942.             parse_word(ps, 0, 0);
  1943.             strncpy(sobj->name, ps, 18);
  1944.             sobj->name[18] = '\0';
  1945.         } else if (strcmp(name, "STGF")==0) { sobj->stgf = get_UWORD();
  1946.         } else if (strcmp(name, "OSIZ")==0) { process_OSIZ(sobj, world);
  1947.         } else if (strcmp(name, "POSN")==0) { process_POSN(sobj, world);
  1948.         } else if (strcmp(name, "ALGN")==0) { process_ALGN(sobj, world);
  1949.         } else if (strcmp(name, "PALN")==0) { process_PALN(sobj, world);
  1950.         } else if (strcmp(name, "TALN")==0) { process_TALN(sobj, world);
  1951.         } else if (strcmp(name, "HING")==0) { process_HING(sobj, world);
  1952.         } else if (strcmp(name, "PTH2")==0) { process_PTH2(sobj, world);
  1953.         } else if (strcmp(name, "GLB2")==0) { process_GLB2(sobj, world);
  1954.         } else if (strcmp(name, "AXIS")==0) { process_AXIS(sobj, world);
  1955.         } else if (strcmp(name, "LITE")==0) { process_LITE(sobj, world);
  1956.         } else if (strcmp(name, "FILE")==0) { process_FILE(sobj, world);
  1957.         } else if (strcmp(name, "END")==0) {
  1958.             parse_word(name, 4, 1);
  1959.             if (strcmp(name, "SOBJ")!=0)
  1960.                 fprintf(stderr, "WARNING: Line %d: Expected 'END SOBJ' but got: 'END %s'\n", world->cur_line, name);
  1961.             parse_word(ps, 0, 0);    /* Get the quote, if any */
  1962.             if (strcmp(this_level, ps)!=0)
  1963.                 fprintf(stderr, "WARNING: Line %d: 'SOBJ Begin' and 'End SOBJ' quoted comments do not match\n", world->cur_line);
  1964.             break;
  1965.         } else {
  1966.             if (verbose_flag)
  1967.                 fprintf(stderr, "WARNING: Line %d: Unknown SOBJ sub-sub-chunk: '%s'\n",
  1968.                     world->cur_line, name);
  1969.             continue;
  1970.         }
  1971.     }
  1972. }
  1973.  
  1974. static void process_OSIZ(sobj, world)
  1975. SOBJ *sobj;
  1976. WORLD *world;
  1977. {
  1978.     char name[5];
  1979.     register OSIZ *osiz;
  1980.  
  1981.     if (!(osiz = (OSIZ*)malloc(sizeof(OSIZ)))) OUT_MEM("OSIZ");
  1982.     bzero((char*)osiz, sizeof(OSIZ));
  1983.     osiz->start = osiz->stop = 1;
  1984.     while (1) {
  1985.         parse_word(name, 4, 1);
  1986.         if (!name[0]) break;
  1987.         if      (strcmp(name, "FLAG")==0) osiz->flags = get_UWORD();
  1988.         else if (strcmp(name, "STAR")==0) osiz->start = get_UWORD();
  1989.         else if (strcmp(name, "STOP")==0) osiz->stop  = get_UWORD();
  1990.         else if (strcmp(name, "SIZE")==0) stuff_XYZ(&osiz->size);
  1991.         else {
  1992.             if (verbose_flag)
  1993.                 fprintf(stderr, "WARNING: Line %d: Unknown OSIZ sub-sub-chunk: '%s'\n",
  1994.                     world->cur_line, name);
  1995.         }
  1996.     }
  1997.     insert_into_sorted_list((PALN**)&sobj->osiz, (PALN*)osiz);
  1998. }
  1999.  
  2000. static void process_POSN(sobj, world)
  2001. SOBJ *sobj;
  2002. WORLD *world;
  2003. {
  2004.     char name[5];
  2005.     register POSN *posn;
  2006.  
  2007.     if (!(posn = (POSN*)malloc(sizeof(POSN)))) OUT_MEM("POSN");
  2008.     bzero((char*)posn, sizeof(POSN));
  2009.     posn->start = posn->stop = 1;
  2010.     while (1) {
  2011.         parse_word(name, 4, 1);
  2012.         if (!name[0]) break;
  2013.         if      (strcmp(name, "FLAG")==0) posn->flags = get_UWORD();
  2014.         else if (strcmp(name, "STAR")==0) posn->start = get_UWORD();
  2015.         else if (strcmp(name, "STOP")==0) posn->stop  = get_UWORD();
  2016.         else if (strcmp(name, "POSN")==0) stuff_XYZ(&posn->posn);
  2017.         else {
  2018.             if (verbose_flag)
  2019.                 fprintf(stderr, "WARNING: Line %d: Unknown POSN sub-sub-chunk: '%s'\n",
  2020.                     world->cur_line, name);
  2021.         }
  2022.     }
  2023.     insert_into_sorted_list((PALN**)&sobj->posn, (PALN*)posn);
  2024. }
  2025.  
  2026. static void process_ALGN(sobj, world)
  2027. SOBJ *sobj;
  2028. WORLD *world;
  2029. {
  2030.     char name[5];
  2031.     register ALGN *algn;
  2032.  
  2033.     if (!(algn = (ALGN*)malloc(sizeof(ALGN)))) OUT_MEM("ALGN");
  2034.     bzero((char*)algn, sizeof(ALGN));
  2035.     algn->start = algn->stop = 1;
  2036.     while (1) {
  2037.         parse_word(name, 4, 1);
  2038.         if (!name[0]) break;
  2039.         if      (strcmp(name, "FLAG")==0) algn->flags = get_UWORD();
  2040.         else if (strcmp(name, "STAR")==0) algn->start = get_UWORD();
  2041.         else if (strcmp(name, "STOP")==0) algn->stop  = get_UWORD();
  2042.         else if (strcmp(name, "ALGN")==0) stuff_XYZ(&algn->algn);
  2043.         else {
  2044.             if (verbose_flag)
  2045.                 fprintf(stderr, "WARNING: Line %d: Unknown ALGN sub-sub-chunk: '%s'\n",
  2046.                     world->cur_line, name);
  2047.         }
  2048.     }
  2049.     insert_into_sorted_list((PALN**)&sobj->algn, (PALN*)algn);
  2050. }
  2051.  
  2052. static void process_PALN(sobj, world)
  2053. SOBJ *sobj;
  2054. WORLD *world;
  2055. {
  2056.     char name[5];
  2057.     register PALN *paln;
  2058.  
  2059.     if (!(paln = (PALN*)malloc(sizeof(PALN)))) OUT_MEM("PALN");
  2060.     bzero((char*)paln, sizeof(PALN));
  2061.     paln->start = paln->stop = 1;
  2062.     while (1) {
  2063.         parse_word(name, 4, 1);
  2064.         if (!name[0]) break;
  2065.         if      (strcmp(name, "FLAG")==0) paln->flags = get_UWORD();
  2066.         else if (strcmp(name, "STAR")==0) paln->start = get_UWORD();
  2067.         else if (strcmp(name, "STOP")==0) paln->stop  = get_UWORD();
  2068.         else {
  2069.             if (verbose_flag)
  2070.                 fprintf(stderr, "WARNING: Line %d: Unknown PALN sub-sub-chunk: '%s'\n",
  2071.                     world->cur_line, name);
  2072.         }
  2073.     }
  2074.     insert_into_sorted_list(&sobj->paln, paln);
  2075. }
  2076.  
  2077. static void process_TALN(sobj, world)
  2078. SOBJ *sobj;
  2079. WORLD *world;
  2080. {
  2081.     char name[5];
  2082.     register TALN *taln;
  2083.  
  2084.     if (!(taln = (TALN*)malloc(sizeof(TALN)))) OUT_MEM("TALN");
  2085.     bzero((char*)taln, sizeof(TALN));
  2086.     taln->start = taln->stop = 1;
  2087.     while (1) {
  2088.         parse_word(name, 4, 1);
  2089.         if (!name[0]) break;
  2090.         if      (strcmp(name, "FLAG")==0) taln->flags = get_UWORD();
  2091.         else if (strcmp(name, "STAR")==0) taln->start = get_UWORD();
  2092.         else if (strcmp(name, "STOP")==0) taln->stop  = get_UWORD();
  2093.         else if (strcmp(name, "INIT")==0) taln->initial_y = get_FRACT();
  2094.         else if (strcmp(name, "FINA")==0) taln->final_y   = get_FRACT();
  2095.         else if (strcmp(name, "TRAC")==0 || strcmp(name, "NAME")==0 ||
  2096.             strcmp(name, "OBJE")==0) {
  2097.             parse_word(taln->trackobj, 0, 0);
  2098.         } else {
  2099.             if (verbose_flag)
  2100.                 fprintf(stderr, "WARNING: Line %d: Unknown TALN sub-sub-chunk: '%s'\n",
  2101.                     world->cur_line, name);
  2102.         }
  2103.     }
  2104.     insert_into_sorted_list((PALN**)&sobj->taln, (PALN*)taln);
  2105. }
  2106.  
  2107. static void process_HING(sobj, world)
  2108. SOBJ *sobj;
  2109. WORLD *world;
  2110. {
  2111.     char name[5];
  2112.     register HING *hing;
  2113.  
  2114.     if (!(hing = (HING*)malloc(sizeof(HING)))) OUT_MEM("HING");
  2115.     bzero((char*)hing, sizeof(HING));
  2116.     hing->start = hing->stop = 1;
  2117.     while (1) {
  2118.         parse_word(name, 4, 1);
  2119.         if (!name[0]) break;
  2120.         if      (strcmp(name, "FLAG")==0) hing->flags = get_UWORD();
  2121.         else if (strcmp(name, "STAR")==0) hing->start = get_UWORD();
  2122.         else if (strcmp(name, "STOP")==0) hing->stop  = get_UWORD();
  2123.         else if (strcmp(name, "NAME")==0) {
  2124.             parse_word(hing->hingeobj, 0, 0);
  2125.         } else {
  2126.             if (verbose_flag)
  2127.                 fprintf(stderr, "WARNING: Line %d: Unknown HING sub-sub-chunk: '%s'\n",
  2128.                     world->cur_line, name);
  2129.         }
  2130.     }
  2131.     insert_into_sorted_list((PALN**)&sobj->hing, (PALN*)hing);
  2132. }
  2133.  
  2134. static void process_PTH2(sobj, world)
  2135. SOBJ *sobj;
  2136. WORLD *world;
  2137. {
  2138.     char name[128];
  2139.     register PTH2 *pth2;
  2140.  
  2141.     if (!(pth2 = (PTH2*)malloc(sizeof(PTH2)))) OUT_MEM("PTH2");
  2142.     bzero((char*)pth2, sizeof(PTH2));
  2143.     pth2->start = pth2->stop = 1;
  2144.     while (1) {
  2145.         parse_word(name, 0, 1);        /* Don't limit the word size */
  2146.         if (!name[0]) break;
  2147.         if      (strncmp(name, "FLAG",4)==0) pth2->flags = get_UWORD();
  2148.         else if (strcmp(name, "START")==0) pth2->start = get_UWORD();
  2149.         else if (strncmp(name, "STOP",4)==0) pth2->stop  = get_UWORD();
  2150.         else if (strncmp(name, "ACCE",4)==0) pth2->acceleration_frames = get_ULONG();
  2151.         else if (strncmp(name, "START_",6)==0) pth2->start_speed=get_FRACT();
  2152.         else if (strncmp(name, "DECEL",5)==0) pth2->deacceleration_frames = get_ULONG();
  2153.         else if (strncmp(name, "END_",4)==0) pth2->end_speed = get_FRACT();
  2154.         else if (strcmp(name, "PATH")==0 || strcmp(name, "NAME")==0) {
  2155.             parse_word(pth2->path, 0, 0);
  2156.         } else {
  2157.             if (verbose_flag)
  2158.                 fprintf(stderr, "WARNING: Line %d: Unknown PTH2 sub-sub-chunk: '%s'\n",
  2159.                     world->cur_line, name);
  2160.         }
  2161.     }
  2162.     insert_into_sorted_list((PALN**)&sobj->pth2, (PALN*)pth2);
  2163. }
  2164.  
  2165. static void process_GLB2(sobj, world)
  2166. SOBJ *sobj;
  2167. WORLD *world;
  2168. {
  2169.     char name[128];
  2170.     register GLB2 *glb2;
  2171.  
  2172.     if (!(glb2 = (GLB2*)malloc(sizeof(GLB2)))) OUT_MEM("GLB2");
  2173.     bzero((char*)glb2, sizeof(GLB2));
  2174.     glb2->start = glb2->stop = 1;
  2175.     while (1) {
  2176.         parse_word(name, 0, 1);        /* Don't limit the word size */
  2177.         if (!name[0]) break;
  2178.         if      (strncmp(name, "FLAG",4)==0) glb2->flags = get_UWORD();
  2179.         else if (strcmp(name, "START")==0) glb2->start = get_UWORD();
  2180.         else if (strcmp(name, "STOP")==0) glb2->stop  = get_UWORD();
  2181.         else if (strncmp(name, "SKY_",4)==0) glb2->sky_blending = get_ULONG();
  2182.         else if (strncmp(name, "STARF",5)==0) glb2->starfield = get_FRACT();
  2183.         else if (strncmp(name, "TRAN",4)==0) glb2->transition = get_ULONG();
  2184.         /* The following are FRACTional colors */
  2185.         else if (strncmp(name, "AMBI",4)==0) stage_RGB(&glb2->ambient);
  2186.         else if (strncmp(name, "HORI",4)==0) stage_RGB(&glb2->horizon);
  2187.         else if (strcmp(name, "ZENITH1")==0) stage_RGB(&glb2->zenith1);
  2188.         else if (strcmp(name, "ZENITH2")==0) stage_RGB(&glb2->zenith2);
  2189.         else if (strncmp(name, "FOG_C",5)==0) stage_RGB(&glb2->fog_color);
  2190.         else if (strncmp(name, "FOG_B",5)==0) glb2->fog_bottom = get_FRACT();
  2191.         else if (strncmp(name, "FOG_T",5)==0) glb2->fog_top    = get_FRACT();
  2192.         else if (strncmp(name, "FOG_L",5)==0) glb2->fog_length = get_FRACT();
  2193.         else if (strncmp(name, "BRUSH_S",7)==0) glb2->brush_seq  = get_ULONG();
  2194.         else if (strncmp(name, "BACKDROP_S",10)==0) glb2->backdrop_seq = get_ULONG();
  2195.         else if (strcmp(name, "BACKDROP")==0) {
  2196.             parse_word(glb2->backdrop, 0, 0);
  2197.         } else if (strncmp(name, "GLOB",4)==0) {
  2198.             parse_word(glb2->globalbrush, 0, 0);
  2199.         } else {
  2200.             if (verbose_flag)
  2201.                 fprintf(stderr, "WARNING: Line %d: Unknown PTH2 sub-sub-chunk: '%s'\n",
  2202.                     world->cur_line, name);
  2203.         }
  2204.     }
  2205.     insert_into_sorted_list((PALN**)&sobj->glb2, (PALN*)glb2);
  2206. }
  2207.  
  2208. static void process_AXIS(sobj, world)
  2209. SOBJ *sobj;
  2210. WORLD *world;
  2211. {
  2212.     char name[5];
  2213.     register SAXIS *axis;
  2214.  
  2215.     if (!(axis = (SAXIS*)malloc(sizeof(SAXIS)))) OUT_MEM("SAXIS");
  2216.     bzero((char*)axis, sizeof(SAXIS));
  2217.     axis->start = axis->stop = 1;
  2218.     while (1) {
  2219.         parse_word(name, 4, 1);
  2220.         if (!name[0]) break;
  2221.         if      (strcmp(name, "FLAG")==0) axis->flags = get_UWORD();
  2222.         else if (strcmp(name, "STAR")==0) axis->start = get_UWORD();
  2223.         else if (strcmp(name, "STOP")==0) axis->stop  = get_UWORD();
  2224.         else {
  2225.             if (verbose_flag)
  2226.                 fprintf(stderr, "WARNING: Line %d: Unknown AXIS sub-sub-chunk: '%s'\n",
  2227.                     world->cur_line, name);
  2228.         }
  2229.     }
  2230.     insert_into_sorted_list((PALN**)&sobj->axis, (PALN*)axis);
  2231. }
  2232.  
  2233. static void process_LITE(sobj, world)
  2234. SOBJ *sobj;
  2235. WORLD *world;
  2236. {
  2237.     char name[5];
  2238.     register LITE *lite;
  2239.  
  2240.     if (!(lite = (LITE*)malloc(sizeof(LITE)))) OUT_MEM("LITE");
  2241.     bzero((char*)lite, sizeof(LITE));
  2242.     lite->start = lite->stop = 1;
  2243.     while (1) {
  2244.         parse_word(name, 4, 1);
  2245.         if (!name[0]) break;
  2246.         if      (strcmp(name, "FLAG")==0) lite->flags = get_UWORD();
  2247.         else if (strcmp(name, "STAR")==0) lite->start = get_UWORD();
  2248.         else if (strcmp(name, "STOP")==0) lite->stop  = get_UWORD();
  2249.         /* The following is a FRACTional color */
  2250.         else if (strcmp(name, "COLO")==0) stage_RGB(&lite->color);
  2251.         else if (strcmp(name, "TRAN")==0) lite->transition = get_ULONG();
  2252.         else {
  2253.             if (verbose_flag)
  2254.                 fprintf(stderr, "WARNING: Line %d: Unknown LITE sub-sub-chunk: '%s'\n",
  2255.                     world->cur_line, name);
  2256.         }
  2257.     }
  2258.     insert_into_sorted_list((PALN**)&sobj->lite, (PALN*)lite);
  2259. }
  2260.  
  2261. static void process_FILE(sobj, world)
  2262. SOBJ *sobj;
  2263. WORLD *world;
  2264. {
  2265.     char name[5];
  2266.     register SFILE *file;
  2267.  
  2268.     if (!(file = (SFILE*)malloc(sizeof(SFILE)))) OUT_MEM("SFILE");
  2269.     bzero((char*)file, sizeof(SFILE));
  2270.     file->start = file->stop = 1;
  2271.     while (1) {
  2272.         parse_word(name, 4, 1);
  2273.         if (!name[0]) break;
  2274.         if      (strcmp(name, "FLAG")==0) file->flags = get_UWORD();
  2275.         else if (strcmp(name, "STAR")==0) file->start = get_UWORD();
  2276.         else if (strcmp(name, "STOP")==0) file->stop  = get_UWORD();
  2277.         else if (strcmp(name, "CYCL")==0) file->cycles_to_perform = get_FRACT();
  2278.         else if (strcmp(name, "INIT")==0) file->initial_cycle_phase = get_FRACT();
  2279.         else if (strcmp(name, "TRAN")==0) file->transition = get_ULONG();
  2280.         else if (strcmp(name, "DESC")==0 || strcmp(name, "NAME")==0) {
  2281.             parse_word(file->object_description, 0, 0);
  2282.         } else {
  2283.             if (verbose_flag)
  2284.                 fprintf(stderr, "WARNING: Line %d: Unknown FILE sub-sub-chunk: '%s'\n",
  2285.                     world->cur_line, name);
  2286.         }
  2287.     }
  2288.     insert_into_sorted_list((PALN**)&sobj->file, (PALN*)file);
  2289. }
  2290.  
  2291.